java集合类是一种特别有用的工具类,可以用于存储数量不等的多个对象,并可以实现常用的数据结构,如栈、队列等,而且,还可以用来保存具有映射关系的关联数组。与数组相比,集合功能更强大,使用起来也更方面,只是,集合只能用来保存对象。
哦,集合还真是一个体系庞大的家族。不过大致上,我们可以将集合分为:Set、List、Map、Queue四种体系。Set代表无序、不可重复的集合;List代表有序、重复的集合;Map则代表具有映射关系的集合;Queue代表一种队列集合实现,有点类似List。其中,Set、List、Queue都是根接口Collection的子接口或实现类,Map本身就是一个跟接口。关于collection接口和Map接口的继承树,我们可以用两个图来表示:
对集合进行遍历时,我们可以像遍历数组一样,用foreach循环,也可以用迭代器Iterater。其实,foreach循环实质上也是用Iterater遍历的。很明显,迭代器,提供一种访问一个集合对象各个元素的途径,同时又不需要暴露该对象的内部细节。Iterater首先通过hasNext()作为迭代条件,再用next()方法得到每一个元素,最后进行相关操作。Iterater还有一种不太常用的方法remove(),从Collection中移除最后一个元素。
接口collection提供了对List进行操作的多个方法,其中我们可能常用的有:
Static void sort(List list):根据元素的自然顺序对list按升序进行排序;
Static void sort(List list,Comparator c):根据指定的Comparator产生的顺序对list的元素进行排序;
Static void reverse(List list):发转指定List;
Static void swap(List list,int i,int j):将指定List集合中的i元素和j元素交换;
关于集合排序问题,对于没有排序功能的集合,都可以用Collection的sort()方法进行排序,它除了集合对象以外还需要提供一个比较器。如果列表中的元素全部都是相同类型的,并且这个类实现了Comparable接口,可以直接简单的调用Collection.sort()。如果这个类没有实现Comparable接口,就可以传递一个Comparator实例作为sort()的第二个参数进行排序。另外,如果不想使用默认的分类顺序进行排序,同样可以传递一个Compatator实例作为参数进行排序。
Comparable接口和Comparaor接口都是用来比较两个实例之间的大小关系的。对于Comparatable接口来说,它往往是进行比较类需要实现的接口,它仅仅含有一个comparaeTo()方法,只有一个参数,返回值为int类型数据。返回值大于0时,表示本对象对象大于参数对象,小于0时,表示本对象小于参数对象,等于0表示二者相等。Comparator也是一个接口,它的实现者被称为比较器。它包含一个comparae()方法,有两个参数,返回值与Comparable的compare()方法一样。不同之处在于Comparator接口一般不会被集合类所实现,而是单独显现或用匿名内部类的方式来实现。
List:List接口是collection接口的子接口,因为List是有序集合,所以,除了collection接口中定义的方法之外,list还增加了一些根据索引来操作集合的方法。我们所熟悉的list.get(int i)是根据索引返回集合元素,add(Object element)是继承自collection的方法,除此之外,我们可能还会用到下面的几种方法:
void add(int index,Object element):将元素element插入到List集合的index处;
boolean addAll(int index,Collection c):将集合c所包含的的所有元素插入到List集合的index处;
int indexOf(Object element):返回对象element在List集合中出现的位置索引;
Object .remove(int index):删除并返回index索引处的元素;
Object set(int index,Object elment):将index索引处的元素替换成element对象,并返回新元素;
List subList(int fromIndex,int toIndex):返回从索引fromIndex(包含)到索引toIndex(不包含)处的所有集合元素组成的子集合。使用subList方法时要对子集合的修改会影响到原来的集合。我们可以看一下下面这段代码:
运行结果:

我们可以看到,用subList方法成功截取了list1中index从1到4的元素,不过,也证明了对子List进行操作时,原来的List也发生了改变。所以,当我们使用sublist方法时,一定要注意是否要求对子集合进行操作而不能影像原来的集合。
前面我们新建一个List实例时用的是ArrayList,ArrayList是List的一个实现类,可以直接用来创建List对象。同ArrayList一样,Vector也是List的一个实现类。用法几乎和ArrayList相同。只是ArrayList是线程不安全的,当多条线程访问同一个ArrayList时,如果有超过一条线程修改了ArrayList集合,程序就必须要手动保证集合的同步性。而Vector是线程安全的,无需保证集合的同步性。
除此之外,List还有一个LinkedList的实现,它是一个基于链表实现的List类,对顺序访问集合中的元素进行了优化,特别是插入、删除元素的速度特别快。另外,LinkedList也实现了Deque接口(双向队列)。不同的容器在进行不同的操作时性能是不一样的。下表列出了array、ArrayList、Vector和LinkedList的性能差异:
实现机制 | 随机访问排名 | 迭代操作排名 | 插入操作排名 | 删除操作排名 | |
Array | 连续内存区保存元素 | 1 | 不支持 | 不支持 | 不支持 |
ArrayList | 内部以数组保存元素 | 2 | 2 | 2 | 2 |
Vector | 内部以数组保存元素 | 3 | 3 | 3 | 3 |
LinkedList | 内部以链表保存元素 | 4 | 1 | 1 | 1 |
如果要遍历List集合的元素,如果要经常随机访问可以使用ArrayList和Vector,用get方法进行遍历;
如果需要经常执行插入、删除操作来改变List集合的大小,应该用LinkedList,使用ArrayList和Vector经常需要重新分配内存数组的大小,时间开销是LinkedList的几十倍。
如果有多条线程同时访问List,用线程安全的Vector。
Map用于保存具有映射关系的数据,因为Map集合里保存着两组值,一组用于保存Map里的key,另一组用于保存Map里的value,key和value都可以是任何引用数据类型的数据。但是key不允许重复,所以通过指定的key值得到的value值总是唯一的。我们通常所用的是Map的实现类HashMap和HashTable。同ArrayList和Vector相似,HashMap是线程不安全的实现,而HashTable是线程安全的实现类.另外,HashTable不允许将null作为key或value值,否则会出现NullPointException异常;HashMap可以用null作为key或value值。