Java集合类是一个特别有用的工具类,可以用于存储数量不等的多个对象,并可实现常用的数据结构。
Java集合大致可以分为:Set、List、Map三种体系:

  • Set:代表无序、不可重复的集合
  • List:代表有序、可重合的集合
  • Map:代表具有映射关系的集合

Java集合类主要由两个接口派生而来:Collection和Map,Collection和Map是java集合框架的根接口。Collection接口的继承树如下图所示:
Collection Map接口继承树如下图所示:
Map 使用Iterator接口可以遍历集合元素,Iterator本身并不提供盛装对象的能力。当使用Iterator对集合里的元素进行迭代时,Iterator并不是把集合本身传递给迭代变量,而是把集合元素的值传给迭代变量,所以修改迭代变量的值对集合元素本身没有任何影响,但可以删除。
[Java Code]

public void iterator(){
        Collection books=new ArrayList();
        books.add("a");
        books.add("b");
        books.add("c");
        Iterator it=books.iterator();
        while(it.hasNext()){
            String book=(String)it.next();
            book="d";
        }
        System.out.println(books.toString());
    }

输出a,b,c

Iterator是fail-fast机制,一旦在迭代过程中检测到该集合已经被修改过,程序立即引发ConcurrentModificationException异常。Iterator方法的工作原理如下图所示: Iterator

Set集合:判断两个对象相同不是用==运算符,而是用equals方法。因此可以修改equals方法来添加相同的元素。

HashSet类:不是同步的,允许null值,HashSet底层实际上是一个HashMap,把<key,value>值封装成一个Map.Entry类,通过Entry类中的key来比较添加的值。HashSet判断两个对象相等的标准是通过equals方法比较相等,并且hashCode方法返回一样的值。当hashCode相同,当equals不同,元素会以链式存储,影响性能。如果修改一个HashSet中的值可能会出现混乱,因为hashCode可能会根据对象的值计算,当改掉该值时,该对象依然存储在原来的hashCode上,但是再次访问它计算hashCode就不是原来的位置了。

LinkedHashSet类:维护元素的插入顺序,因此性能略低于HashSet,但在迭代访问Set里的全部元素时将有很好的性能,因为它以链表来维护内部顺序。该类底层实现是LinkedHashMap类,维护了一个双重链接列表。此链接列表定义了迭代顺序,该类不是同步的。

TreeSet类:是SortedSet接口的实现类,可以确保集合元素处于排序状态。TreeSet是通过比较元素大小来排序,而不是插入顺序,所以要求元素直接必须要是可比较的,如果把一个对象添加到TreeSet中,则该对象的类必须实现Comparable接口,否则程序会抛出异常。TreeSet使用两种排序方法:自然排序和定制排序。

  • 自然排序:调用元素的compareTo方法,按元素的升序排序。编程时要尽量确保equals方法和compareTo方法保持一致性。如果TreeSet中包含了可变对象,当可变对象的Field被修改时,TreeSet在处理这些对象时将会非常复杂,而且容易出错。
  • 定制排序:通过Comparator接口来重写compareTo方法。

TreeSet类是线程非安全的,源码中是用TreeMap来实现的,而TreeMap采用红黑树的结构来存储数据,是一种自平衡的排序二叉树,TreeSet把<key,value>值封装成Entry类来表示红黑树的一个节点。

EnumSet类:EnumSet类是一个专门为枚举类设计的集合类。EnumSet的集合元素必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显示或隐式指定。不允许加入null值。

可以通过Collection工具类的synchronizedSortedSet方法来包装Set集合的同步性。

SortedSet s=Collections.synchronizedSortedSet(new TreeSet(…));

List集合代表一个元素有序、可重复的集合,集合中每个元素都有其对应的顺序索引。List接口还提供了listIterator方法,该方法返回一个ListIterator对象,ListIterator接口继承Iterator接口,还专门提供了一个前向迭代的功能,而且还可以通过add方法向List集合中添加元素(Iterator只能删除元素)。

ArrayList和Vector都是基于数组实现的List,底层的数据结构是数组,所以ArrayList和Vector类封装了一个动态的、允许再分配的Object[]数组。两个类都通过initialCapacity参数来设置该数组的长度,当向其中添加元素超出该数组长度时,它们的initialCapacity会自动增加。ArrayList是线程不安全的,而Vector是线程安全的。所以Vector的性能要比ArrayList的性能低。Vector还有个子类Stack,也是线程安全的,模仿了栈的操作

Queue用于模拟队列这种数据结构,FIFO。Deque代表一个双端队列,可以同时从两端来添加、删除元素,所以可以当成栈来使用。PriorityQueue保存队列元素的顺序并不是按加入队列的顺序,而是按照队列元素大小进行重新排序。

Deque接口提供了一个实现类ArrayDeque,是基于数组实现的双端队列,底层也是一个Object[]数组来保存元素,如果超出容量,则会重新分配一个Object[]数组来存储集合元素。因为Stack是线程安全的,所以性能较ArrayDeque和LinkedList较差,所以栈结构推荐使用ArrayDeque和LinkedList。

LinkedList类实现了Deque接口,所以可以当成栈,它的底层实现方式是链表,因此随机访问集合元素时性能较差,但在插入和删除方面性能非常出色。对于所有内部基于数组实现的集合,使用随机访问的性能比使用Iterator迭代访问的性能要好,因为随机访问数组会被映射成对数组元素的访问。