List集合接口主要使用类
本章主要复习实现list接口的几个类,侧重于说明简单的使用方法和基本注意事项以及各个的使用优缺点。
List代表一个元素有序,可以重复的集合,集合中的每个元素都有其对应的顺序索引。
List集合是Collection集合的子接口,因此有Collection的很多方法,而List又新增加了很多根据索引操作元素的集合。
Void add(int I ,Object obj);
BooleanaddAll(int index,Collection c);
IntindexOf(Object o);
Object remove(int index);
Int lastIndexOf(intindex);
Object set(intindex,Object obj);
List subList(int fromIndex, int toIndex);
与set集合相比List增加了根据索引来插入,替换和删除集合元素的方法。
首先是ArrayList的演示。
实例代码一:
package cn.com.list;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/**
*
* @author fcs
* List接口的实现类练习测试:ArrayList进行测试,注意另外一个实现类Vector是线程安全的,而ArrayList不是线程安全的
*/
public class ArrayListDemo {
public static void main(String[] args) {
List<String> books = new ArrayList<String>(); //java1.6及以下可以使用这种方式
List foods = new ArrayList(); //由于List接口支持泛型机制因此,在这种情况下会进行泛型检测
/*添加:有四种方式*/
books.add(new String("疯狂java讲义"));
books.add(1, "Effective java中文版");
Collection<String> booksColl = new ArrayList<String>();
booksColl.add("Linux基础");
booksColl.add("计算机网络");
books.addAll(2, booksColl); //添加集合
books.addAll(booksColl);
books.add("疯狂java讲义");
/*查找和遍历*/
boolean b = books.contains("疯狂java讲义");
System.out.println("b = "+b);
boolean b1 = books.containsAll(booksColl); //判断是否包含集合
System.out.println("b1 = "+b1);
String listStr = books.get(2); //说明:虽然我们在上面的第三个位置即索引为2的地方加入到额是集合,
//但是List会往后一个一个的添加,因此再次得到的第二个索引的值是该集合的首元素
System.out.println(listStr);
int index1 = books.indexOf("疯狂java讲义"); //返回该参数中对象的第一次出现的位置,如果没有
System.out.println("index1 = "+index1);
index1 = books.indexOf(2);
System.out.println("index1 = "+index1); //当没有出现的时候则返回-1.
index1 = books.lastIndexOf("疯狂java讲义");
System.out.println("index1 = "+index1); //返回指定元素最后一次出现的位置
ListIterator<String> listIt = books.listIterator(); //正向遍历
while(listIt.hasNext()){ // listIt.hasPrevious():实现反向遍历
System.out.print(listIt.next()+"--");
}
System.out.println();
Iterator<String> listIt1 = books.iterator(); //使用Iterator接口的方法只能实现正向遍历
while(listIt1.hasNext()){
System.out.print(listIt1.next()+"--");
}
System.out.println();
for(int i =0;i<books.size();i++){ //使用for循环遍历,不过这种方式比较低级,在数据量比较大的时候性能不如增强for循环
System.out.print(books.get(i)+"--");
}
System.out.println();
for(String bookStr : books){
System.out.print(bookStr+"--");
}
System.out.println();
listIt = books.listIterator(1); //从指定索引处开始遍历
while(listIt.hasNext()){
System.out.println(listIt.next());
}
/*修改*/
books.set(2, "操作系统");
for(String bookStr : books){
System.out.print(bookStr+"--");
}
books.isEmpty(); //判断集合是否为空
/*删除:*/
//books.clear(); //清空集合,但是该并没有为null,只是里面没有元素而已
System.out.println(books.size()); //获取该集合的大小
System.out.println(books == null ? "true":"false");
//books.remove(2); //通过索引删除指定元素
//books.remove("疯狂java讲义"); //直接删除指定元素
//books.removeAll(booksColl); //删除放入的集合
//b = books.containsAll(booksColl);
//System.out.println("b = "+b);
/*转换*/
String booksList = books.toString(); //转换成String
System.out.println(booksList);
List<String> newbooks = books.subList(0, 3); //截取子集合
System.out.println(newbooks.size());
//String [] booksArray = (String[]) books.toArray(); //这种方式是错误的,在进行强制转换的时候会报错
Object[] booksArray = books.toArray();
System.out.println(booksArray.length);
}
}
上面的方法中有一个接口说明一下:
这个是针对list集合遍历提出的。
List可以通过继承Collection得到的Iterator接口的方法进行遍历,也可以通过listIterator方法进行遍历,返回一个ListIterator对象,而这个ListIterator则继承了Iterator接口,提供了专门操作List的集合。
ListIterator接口在Iterator接口上又增加了下面的几个方法:
1.booleanhasPrevious(); 返回该迭代器关联的集合对象是否还有上一个元素,可以进行逆序遍历。
2.Object previous(); 返回该迭代器的上一个元素
3 .void add(E e); 将指定的元素插入列表中。
而在JDK 1.6的API中对该接口有如下定义:
系列表迭代器,允许程序员按任一方向遍历列表、迭代期间修改列表,并获得迭代器在列表中的当前位置。ListIterator 没有当前元素;它的光标位置 始终位于调用previous() 所返回的元素和调用 next() 所返回的元素之间。长度为 n 的列表的迭代器有n+1 个可能的指针位置。
remove()
和 set(Object)
方法不是 根据光标位置定义的;它们是根据对调用 next()
或 previous()
所返回的最后一个元素的操作定义的
然后是list判断集合元素(对象)相等的测试以及一个帖子引发的测试。
实例代码二:
/**
* List如何判断两个元素对象是否相等
* 说明:list判断两个对象元素是否相等是通过equals方法进行比较的,而且在比较时采用的方法是覆盖Object类的那个方法。
* @author fcs
*
*/
class A{
//注意这里内涵玄机:比较的时候参数要是Object类型的,否则如果直接拿对象进行比较是无法判断新对象元素与已经存在的对象元素
//相等的,原因是该方法判断元素相等是通过Object超类的equals方法判断的,如果参数类型不是Object类型则不能覆盖,也就是说是方法重载的问题。
//这也是CSDN上面博友讨论的一个问题,在这里说一下,下面给出一个例子
public boolean equals(Object obj){
return true;
}
}
public class ListEquals {
public static void main(String[] args) {
List<String> booksList = new ArrayList<String>();
booksList.add(new String("A"));
booksList.add(new String("B"));
booksList.add("C");
booksList.add("D");
System.out.println(booksList.toString());
booksList.remove(new A()); //这里每次比较都会通过equals方法,设置默认每次都为true,因此每次比较都会删除第一个元素,而
//而remove的方法参数为Object类型。
System.out.println(booksList.toString());
booksList.remove(new A());
System.out.println(booksList.toString());
/*----------下面我们来看CSDN上面的一个帖子的问题:List判断两个对象是通过equals方法进行的?----------*/
Product p1 = new Product(1,"A");
Product p2 = new Product(2,"B");
Product p3 = new Product(3,"C");
Product p2_1 = new Product(2, "X"); //当然这里只是以id为判断标准,也可以以两个都为判断标准
List<Product> proList = new ArrayList<Product>();
proList.add(p1);
proList.add(p2);
proList.add(p3);
// //测试一:以第一个equals方法为准。
// for(Product pro : proList){
// if(p2_1.equals(pro)){
// System.out.println("true");
// }
// }
// System.out.println(proList.indexOf(p2_1)); //这里返回的是-1,也就是说没有id=2的元素,问题就在这里。
//
//
// //测试二:以第二个equals方法为准。
// for(Product pro : proList){
// if(p2_1.equals(pro)){
// System.out.println("true");
// }
// }
// System.out.println(proList.indexOf(p2_1)); //这里会返回1,表明第二个equals方法可以达到通过id判断是否相等的要求。
//
//测试三:以第三个equals方法为准,编辑器以两个属性作为判断标准,将p2_1的name值再改为B进行测试
for(Product pro : proList){
if(p2_1.equals(pro)){
System.out.println("true");
}
}
System.out.println(proList.indexOf(p2_1)); //p2_1.name = B返回1,当p2_1.name = X,返回-1
//注意这种比较方式与hashcode方法没有关系,下面没有重写该方法同样可以实现测试要求和目的。
}
}
class Product{
private int id;
private String name;
public Product(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// //第一种equals方法,这种方式算与下面的equals方法是重载的关系
// public boolean equals(Product p){
// if(this.id == p.getId()){
// return true;
// }
// return false;
// }
// @Override //注意在重写方法的时候加上这个注解就会少很多错。
// public boolean equals(Object p){
// //当然这里的对象要进行一次强制转换
// Product pro = (Product)p;
// if(this.id == pro.getId()){
// return true;
// }
// return false;
// }
//另外我们通过eclipse的编辑器自动生成的比较方法也可以看出是这种结果,这是一种比较标准的写法
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Product other = (Product) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
在CSDN上的这个帖子的一个博友回答可以使用实现Comparable接口的方式进行判断,因此我也针对这个方法进行了与楼主同样的测试,测试结果说明都在代码中的注释里,这里就不赘述了。
实例代码三:
/**
* List中比较两个对象想的方式:通过Comparable接口进行比较两个对象的方式,
* 当然Comparable接口着重于进行排序,
* @author fcs
*
*/
@SuppressWarnings("rawtypes")
class Foods implements Comparable{
private int id;
private String name;
public Foods(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int compareTo(Object o) { //这里要实现的方法同样要进行类型转换
Foods foods = (Foods)o;
return foods.getId() - this.getId();
}
}
public class ListEquals_2 {
public static void main(String[] args) {
List<Foods> strList = new ArrayList<Foods>();
strList.add(new Foods(1,"蔬菜"));
strList.add(new Foods(2,"水果"));
strList.add(new Foods(3,"肉类"));
Foods foods = new Foods(2,"水果");
for(Foods strFoods : strList){
if(strFoods.compareTo(foods) == 0){
System.out.println("true"); //会输出为true,可以达到通过对象的id进行相等的测试,
//不过这里实际上采用了比较低级的方式:是通过遍历进行的测试。
}
}
int b = strList.indexOf(foods); //但是这里输出的是-1,说明不是同一个对象。所以使用Comparable接口进行比较实际上不能满足性能上的要求
System.out.println("b = "+b);
}
}
第二 实现List的Stack和Vector说明:
ArrayList和Vector都是作为List类的两个基本实现,而且是基于数组的实现方式。其中有一个属性是initialCapacity参数,通过该参数可以设置该数组的长度。在一次性添加大量的元素时,可以使用ensureCapacity(int minCapacity)方法一次性增加initialCapacity的值,可以减少重分配的次数,提高性能。
如果知道需要多少空间存储元素,则可以在创建的时候就指明initialCapacity的大小、
除此之外:下面了的两个方法可以帮助重新分配Object[]数组的空间:
Void ensureCapacity(int mincapacity)将ArrayList或者、Vector集合的Object[]数组长度增加minCapacity;
Void trimToSize(): 调整ArrayList或者Vector集合元素的object[]数组的长度为当前元素的个数,这样可以减少ArrayList和Vector对象占用的空间。
第三: 固定长度的List:
实例代码,四import java.util.Arrays;
import java.util.List;
/**
* 固定长度的list
* Arrays.ArrayList是一个固定长度的list集合
* @author fcs
*
*/
public class ArrayList {
public static void main(String[] args) {
List fixedList = Arrays.asList("javaman","jsgirl");
System.out.println(fixedList.getClass()); //注意这里输出的是.Arrays$ArrayList是Arrays的内部类arrayList的实例。
for(int i =0;i<fixedList.size();i++){
System.out.println(fixedList.get(i));
}
//试图增加,删除元素都将引发UnsupportedOperationException
fixedList.add("zhangsan");
fixedList.remove(2);
}
}
这里引用了前面的Arrays操作数组的工具类,里面的asList(object … a)方法,该方法可以把一个数组或指定个数的对象转换成一个List集合,这个集合比较特殊:
既不是ArrayList类的实现类,也不是Vector的实现类,而是Arrays的内部类ArrayList的实例:
Arrays.ArraList是一个固定长度的List的集合,程序只能遍历该集合里的元素,不能增加,删除该集合里的元素。
实例代码五:
import java.util.Arrays;
import java.util.List;
/**
* 固定长度的list
* Arrays.ArrayList是一个固定长度的list集合
* @author fcs
*
*/
public class ArrayList {
public static void main(String[] args) {
List fixedList = Arrays.asList("javaman","jsgirl");
System.out.println(fixedList.getClass()); //注意这里输出的是.Arrays$ArrayList是Arrays的内部类arrayList的实例。
for(int i =0;i<fixedList.size();i++){
System.out.println(fixedList.get(i));
}
//试图增加,删除元素都将引发UnsupportedOperationException
fixedList.add("zhangsan");
fixedList.remove(2);
}
}
第四:List接口的LinkedList的实现类:
该实现类不仅实现了List而且实现了Deque接口,因此可以被当成双端队列实现,也可以当成特殊的栈使用。
下面是简单的实例:
实例代码六:
import java.util.LinkedList;
/**
* LinkedList的简单介绍:
* linkedList实现了List,Deque,Queue,List接口,因此可以当做链表集合,可以实现队列,双端队列和栈的功能
*
* @author fcs
*
*/
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("A");
linkedList.add("B");
linkedList.offer("X"); //将字符元素加入队列的尾部
linkedList.add("C");
for(String strlist : linkedList){
System.out.println(strlist);
}
System.out.println(linkedList.peekFirst()); //访问但不删除栈顶元素
System.out.println(linkedList.peekLast()); //访问但不删除队列的最后一个元素
System.out.println(linkedList);
System.out.println(linkedList.pop()); //将栈顶的元素弹出栈,也就是删除栈顶元素
System.out.println(linkedList);
System.out.println(linkedList.pollLast()); //将队列中的最后一个元素删除
System.out.println(linkedList);
}
}
上面的一些其他方法可以在JDK1.6的中文文档中查到,这里就不进行演示了。
本章的一部分代码和原理参考了李刚的疯狂java讲义,同时本系列博客也是全面扫盲的基础和实践,欢迎拍砖交流。