java为开发者提供了一套复杂的容器类型,总体来说共包含三大类实用容器,分别为List、Set和Map,当然还有一类Queue用得特别少,完全能使用List代替,就不再进行介绍。在详细介绍之前,先来看一看他们的关系图(摘自Thinking in java)。

java创建容器对象的类 java容器的构件_java

    

        初看时可能觉得很复杂,难以理解整幅图,不过没关系,可以先阅读下文,待理解了部分类的功能后再回过头来看这幅图,可能有不一样的收获。



        1.collection

        Collection作为最重要最基础的父类,他是一个接口,继承自Iterable接口:

public interface Collection<E> extends Iterable<E>

        Iterable接口含有一个iterator方法用以返回一个Iterator迭代器



public interface Iterable<T> { Iterator<T> iterator(); }



        Iterator接口其中含有2个重要方法,用以遍历序列。Collection实现Iterable后,只需要实现iterator方法,返回一个自定义hasNext函数和next函数的匿名内部类,就能通过这两个函数迭代访问Collection中的元素,非常方便。更多详细介绍请查阅java迭代器的介绍。


boolean hasNext();



E next();



        2.List

    一个 List 是一个元素有序的、可以重复可以为 null 的集合(有时候我们也叫它“序列”)。

    List继承自Collection接口:


public interface List<E> extends Collection<E>


    List含有一些与“列表”有关的方法定义,例如:


int size();
 
 
boolean isEmpty();
 
 
boolean contains(Object o);
 
 
<T> T[] toArray(T[] a);
 
 
boolean add(E e);
 
 
boolean remove(Object o);
 
 
int indexOf(Object o);



   等等,在其实现类里,对这些方法有不同的实现。与众不同的是,List含有一个listIterator,返回一个ListIterator。这个迭代器可不是普通的迭代器,它能正向也能反向迭代,充分利用了LIst的特点。

AbstractList

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E>



AbstractList是具体List类的一个抽象定义,继承自AbstractCollection并且实现了List接口。为什么要继承自AbstractCollection呢,我们来看一看它的源码:



public abstract class AbstractCollection<E> implements Collection<E>



AbstractCollection实现了Collection并且对一些通用方法进行了实现,例如:



public boolean isEmpty() { return size() == 0; }



对不同LIst实现类有不同行为的方法则保持为抽象方法:



public abstract int size();



public abstract Iterator<E> iterator();



现在回到AbstractList,它在AbstractCollection的基础上,对List的通用方法进行了进一步非实现,并且对一些方法进行限制,如果具体类没有重写这些方法,将不能使用这些方法,例如:


public E set(int index, E element) {
    throw new UnsupportedOperationException();
}

其原因是,某些方法如:asList()会返回一个实现了AbstractList的内部类,而该类是固定值,不允许改变元素,因此在调用这些方法时就会产生UnsupportedOperationException,给于警告。

让我们看看AbstractList的实现类,Vector已经过时弃用了,不再介绍。

ArrayList/LinkedList

        ArrayList是最常用的List,它通过维护一个数组保存数据,对随机访问是O(1)的复杂度,但是同数组一样,对于插入和删除,它的需要O(n)的复杂度。



Object[] elementData;


        而与之相反,LinkedList采用链表形式实现了List,对随机访问是O(n)的复杂度,对于插入和删除,它的需要O(1)的复杂度。


Node<E> first


Node<E> last;


    Node用以保存一个节点的数据,它是LinkedList的内部类:

private static class Node<E> {
    E item;
    Node<E> next;
    Node<E> prev;

    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

        其实LinkedList是继承自AbstractSequentialList,AbstractSequentialList继承了AbstractList,它是针对链表式的List进一步实现了部分方法。

 



        3.Set

    在Java中使用Set,可以方便地将需要的类型以集合类型保存在一个列表中。Set是一个不包含重复元素的 Collection。    

    同List一样,Set也是继承自Collection,定义了一些关于“集合”操作的方法。


public interface Set<E> extends Collection<E>

     AbstractSet

    AbstractSet继承自AbstractCollection,并且实现了Set,包含了AbstractCollection中的部分实现,和Set中的独有方法。


public abstract class AbstractSet<E> extends AbstractCollection<E> implements Set<E>

    其实它就实现了3个方法:


public boolean equals(Object o)
 
 
public int hashCode()
 
 
public boolean removeAll(Collection<?> c)

    set中判断元素是否重复,靠的就是equals和hashCode,其重要程度可想而知。

HashSet

        HashSet继承了AbstractSet,实现了Set。


public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable

        对于 HashSet 而言,它是基于 HashMap 实现的,HashSet 底层采用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单。


private transient HashMap<E,Object> map;

        因为采用散列表的方法,HashSet对与查找是非常迅速的,并且因为其元素不能重复的特性,是用来进行元素查重的经常使用的工具。

 LinkedHashSet

        HashSet和LinkedHashSet都是接口Set的实现,两者都不能保存重复的数据。

     主要区别是HashSet不保证集合中元素的顺序,即不能保证迭代的顺序与插入的顺序一致。而LinkedHashSet按照元素插入的顺序进行迭代,即迭代输出的顺序与插入的顺序保持一致。

TreeSet

        与HashSet是基于HashMap实现一样,TreeSet同样是基于TreeMap实现的。TreeMap是一个有序的二叉树,那么同理TreeSet同样也是一个有序的,它的作用是提供有序的Set集合。

        TreeSet在继承了AbstractSet的基础上,实现了NavigableSet。

public class TreeSet<E> extends AbstractSet<E>
    implements NavigableSet<E>, Cloneable, java.io.Serializable


    让我们看看NavigableSet是什么:


public interface NavigableSet<E> extends SortedSet<E>

    看名字就能猜出,这是使TreeSet保持有序的关键原因。

    SortedSet    继承自Set接口。


public interface SortedSet<E> extends Set<E>

    本质上来说,NavigableSet提供了一套二叉树的接口方法,TreeSet利用这些方法实现了二叉树。从而保证了元素的有序性。

 



        4.Map

    Map 是一种把键和值做映射的集合,它的每一个元素都包含一个键象和一个值。 Map没有继承于Collection接口 ,从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。反之亦然。



public interface Map<K,V>



      咋一看,Map的方法很多和Collection相似:


int size();
 
 
boolean isEmpty();
 
 
boolean containsKey(Object key);
 
 
boolean containsValue(Object value);
 
 
V get(Object key);
 
 
V put(K key, V value);
 
 
V remove(Object key);
 
 
Set<K> keySet();
 
 
Collection<V> values();
 
 
Set<Map.Entry<K, V>> entrySet();



        但是其返回值或参数却不一样。containsKey判断是否包含某键,containsValue判断是否包含某值;get通过key获取value,put存放key和value,keySet返回key的集合,values返回value的集合,entrySet返回key,value组的集合。

        AbstractMap

        AbstractMap实现了Map的大部分功能。有所差异的则留给下级类。


public abstract class AbstractMap<K,V> implements Map<K,V>

        这里我只介绍了3种继承自AbstractMap的类,其他的应用场景比较特殊,并不常见。Map实现类的方法是相当复杂的,很多方法可能都不常见,这里只对其原理做简单介绍。

HashMap

     HashMap实现了Map接口,继承AbstractMap。


public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable

    其实现方法也是通过散列表的方法,便于快速通过key查找value。在HashMap中,key-value总是会当做一个整体来处理,系统会根据hash算法来来计算key-value的存储位置,我们总是可以通过key快速地存、取value。

LinkedHashMap

    LinkedHashMap 是HashMap的子类,它可以实现对容器内Entry的存储顺序和对Entry的遍历顺序保持一致。


public class LinkedHashMap<K,V>
    extends HashMap<K,V>
    implements Map<K,V>


       为了实现这个功能,LinkedHashMap内部使用了一个Entry类型的双向链表,用这个双向链表记录Entry的存储顺序。当需要对该Map进行遍历的时候,实际上是遍历的是这个双向链表。

    LinkedHashMap内部使用的LinkedHashMap.Entry类继承自 Map.Ent ry类,在其基础上增加了LinkedHashMap.Entry类型的两个字段,用来引用该Entry在双向链表中的前面的Entry对象和后面的Entry对象。

       它的内部会在 Map.Entry 类的基础上,增加两个Entry类型的引用:before,after。LinkedHashMap使用一个双向连表,将其内部所有的Entry串起来。

TreeMap

        同TreeSet一样,TreeMap也在内部保证了key-value插入的有序性。它继承自AbstractMap,实现了同样奇怪的NavigableMap。


public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable

        来看一看源码,NavigableMap继承自SortedMap,定义了大量红黑树有关的方法,在TreeMap中,通过实现这些方法维护红黑树,实现其有序性。


public interface NavigableMap<K,V> extends SortedMap<K,V>


 



        5.总结

        以上内容对java的Collection内容作了一些简单的总结。因为时间关系,真的很简单,以为每一个内容完全说透,都是一个很漫长的过程。因此,本文只对这些容器作了初步的介绍和结构分析,便于初学者的初步了解,想要继续深入,请看下回分解。。。。