java爲開發者提供了一套複雜的容器類型,整體來講共包含三大類實用容器,分別爲List、Set和Map,固然還有一類Queue用得特別少,徹底能使用List代替,就再也不進行介紹。在詳細介紹以前,先來看一看他們的關係圖(摘自Thinking in java)。java
初看時可能以爲很複雜,難以理解整幅圖,不過不要緊,能夠先閱讀下文,待理解了部分類的功能後再回過頭來看這幅圖,可能有不同的收穫。算法
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();
一個 List 是一個元素有序的、能夠重複、能夠爲 null 的集合(有時候咱們也叫它「序列」)。this
List繼承自Collection接口:spa
public interface List<E> extends Collection<E>
List含有一些與「列表」有關的方法定義,例如:code
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的特色。對象
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是最經常使用的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進一步實現了部分方法。
在Java中使用Set,能夠方便地將須要的類型以集合類型保存在一個列表中。Set是一個不包含重複元素的 Collection。
同List同樣,Set也是繼承自Collection,定義了一些關於「集合」操做的方法。
public interface Set<E> extends Collection<E>
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繼承了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對與查找是很是迅速的,而且由於其元素不能重複的特性,是用來進行元素查重的常用的工具。
HashSet和LinkedHashSet都是接口Set的實現,二者都不能保存重複的數據。
主要區別是HashSet不保證集合中元素的順序,即不能保證迭代的順序與插入的順序一致。而LinkedHashSet按照元素插入的順序進行迭代,即迭代輸出的順序與插入的順序保持一致。
與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利用這些方法實現了二叉樹。從而保證了元素的有序性。
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實現了Map的大部分功能。有所差別的則留給下級類。
public abstract class AbstractMap<K,V> implements Map<K,V>
這裏我只介紹了3種繼承自AbstractMap的類,其餘的應用場景比較特殊,並不常見。Map實現類的方法是至關複雜的,不少方法可能都不常見,這裏只對其原理作簡單介紹。
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 是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串起來。
同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>
以上內容對java的Collection內容做了一些簡單的總結。由於時間關係,真的很簡單,覺得每個內容徹底說透,都是一個很漫長的過程。所以,本文只對這些容器做了初步的介紹和結構分析,便於初學者的初步瞭解,想要繼續深刻,請看下回分解。。。。