標籤:ict 表數 interface 分享圖片 映射 抽象 iter 對象 第一個
Java容器類是java提供的工具包,包含了常用的資料結構:集合、鏈表、隊列、棧、數組、映射等。從本文開始將開啟一個系列詳細分析Java容器中的每個成員,包括原始碼分析,效能分析,不同容器之間對比等等,連結將同步更新在本文和置頂博文內。
Java容器主要可以劃分為4個部分:List列表、Set集合、Map映射、工具類(Iterator迭代器、Enumeration枚舉類、Arrays和Collections)
容器類架構
Java容器工具包架構圖:
通過,可以把握兩個基本主體,即Collection和Map。
-
Collection是一個介面,是高度抽象出來的集合,它包含了集合的基本操作和屬性。Collection包含了List和Set兩大分支。
List是一個有序的隊列,每一個元素都有它的索引。第一個元素的索引值是0。List的實作類別有LinkedList, ArrayList, Vector, Stack。
Set是一個不允許有重複元素的集合。 Set的實作類別有HastSet和TreeSet。HashSet依賴於HashMap,它實際上是通過HashMap實現的;TreeSet依賴於TreeMap,它實際上是通過TreeMap實現的。
-
Map是一個映射介面,即key-value索引值對。Map中的每一個元素包含“一個key”和“key對應的value”。
AbstractMap是個抽象類別,它實現了Map介面中的大部分API。而HashMap,TreeMap,WeakHashMap都是繼承於AbstractMap。
Hashtable雖然繼承於Dictionary,但它實現了Map介面。
-
Iterator是遍曆集合的工具,即我們通常通過Iterator迭代器來遍曆集合。我們說Collection依賴於Iterator,是因為Collection的實作類別都要實現iterator()函數,返回一個Iterator對象。ListIterator是專門為遍曆List而存在的。
-
Enumeration是JDK 1.0引入的抽象類別。作用和Iterator一樣,也是遍曆集合;但是Enumeration的功能要比Iterator少。在上面的框圖中,Enumeration只能在Hashtable, Vector, Stack中使用。
-
Arrays和Collections是運算元組、集合的兩個工具類。
有了上面的整體架構之後,我們接下來對每個類分別進行分析。
Collection介面
Collection的定義如下:
public interface Collection<E> extends Iterable<E> {}
它是一個介面,是高度抽象出來的集合,它包含了集合的基本操作:添加、刪除、清空、遍曆(讀取)、是否為空白、擷取大小、是否保護某元素等等。
在Java中所有實現了Collection介面的類都必須提供兩套標準的建構函式,一個是無參,用於建立一個空的Collection,一個是帶有Collection參數的有參建構函式,用於建立一個新的Collection,這個新的Collection與傳入進來的Collection具備相同的元素。
Collection的API:
abstract boolean add(E object)abstract boolean addAll(Collection<? extends E> collection)abstract void clear()abstract boolean contains(Object object)abstract boolean containsAll(Collection<?> collection)abstract boolean equals(Object object)abstract int hashCode()abstract boolean isEmpty()abstract Iterator<E> iterator()abstract boolean remove(Object object)abstract boolean removeAll(Collection<?> collection)abstract boolean retainAll(Collection<?> collection)abstract int size()abstract <T> T[] toArray(T[] array)abstract Object[] toArray()
List介面
List的定義如下:
public interface List<E> extends Collection<E> {}
List是一個繼承於Collection的介面,即List是集合中的一種。List是有序的隊列,List中的每一個元素都有一個索引;第一個元素的索引值是0,往後的元素的索引值依次+1。和Set不同,List中允許有重複的元素。
官方文檔:A List is a collection which maintains an ordering for its elements. Every element in the List has an index. Each element can thus be accessed by its index, with the first index being zero. Normally, Lists allow duplicate elements, as compared to Sets, where elements have to be unique.
關於API方面。既然List是繼承於Collection介面,它自然就包含了Collection中的全部函數介面;由於List是有序隊列,它也額外的有自己的API介面。主要有“添加、刪除、擷取、修改指定位置的元素”、“擷取List中的子隊列”等。
// Collection的APIabstract boolean add(E object)abstract boolean addAll(Collection<? extends E> collection)abstract void clear()abstract boolean contains(Object object)abstract boolean containsAll(Collection<?> collection)abstract boolean equals(Object object)abstract int hashCode()abstract boolean isEmpty()abstract Iterator<E> iterator()abstract boolean remove(Object object)abstract boolean removeAll(Collection<?> collection)abstract boolean retainAll(Collection<?> collection)abstract int size()abstract <T> T[] toArray(T[] array)abstract Object[] toArray()// 相比與Collection,List新增的API:abstract void add(int location, E object)abstract boolean addAll(int location, Collection<? extends E> collection)abstract E get(int location)abstract int indexOf(Object object)abstract int lastIndexOf(Object object)abstract ListIterator<E> listIterator(int location)abstract ListIterator<E> listIterator()abstract E remove(int location)abstract E set(int location, E object)abstract List<E> subList(int start, int end)
實現List介面的集合主要有:ArrayList、LinkedList、Vector、Stack。
ArrayList
ArrayList定義如下:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
ArrayList是一個動態數組,也是我們最常用的集合。它允許任何符合規則的元素插入甚至包括null。每一個ArrayList都有一個初始容量:
private static final int DEFAULT_CAPACITY = 10;
隨著容器中的元素不斷增加,容器的大小也會隨著增加。在每次向容器中增加元素的同時都會進行容量檢查,當快溢出時,就會進行擴容操作。所以如果我們明確所插入元素的多少,最好指定一個初始容量值,避免過多的進行擴容操作而浪費時間、效率。
size、isEmpty、get、set、iterator 和 listIterator 操作都以固定時間運行。add 操作以分攤的固定時間運行,也就是說,添加 n 個元素需要 O(n) 時間(由於要考慮到擴容,所以這不只是添加元素會帶來分攤固定時間開銷那樣簡單)。
ArrayList擅長於隨機訪問。同時ArrayList是非同步的。
LinkedList
LinkedList定義如下:
public class LinkedList<E> extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
同樣實現List介面的LinkedList與ArrayList不同,ArrayList是一個動態數組,而LinkedList是一個雙向鏈表。所以它除了有ArrayList的基本操作方法外還額外提供了get,remove,insert方法在LinkedList的首部或尾部。
由於實現的方式不同,LinkedList不能隨機訪問,它所有的操作都是要按照雙重鏈表的需要執行。在列表中索引的操作將從開頭或結尾遍曆列表(從靠近指定索引的一端,節約一半時間)。這樣做的好處就是可以通過較低的代價在List中進行插入和刪除操作。
與ArrayList一樣,LinkedList也是非同步的。如果多個線程同時訪問一個List,則必須自己實現訪問同步。一種解決方案是在建立List時構造一個同步的List:
List list = Collections.synchronizedList(new LinkedList(…));
Vector
Vector定義如下:
public class Vector<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
與ArrayList相似,但是Vector是同步的。所以說Vector是安全執行緒的動態數組。它的操作與ArrayList幾乎一樣。
Stack
Stack定義如下:
public class Stack<E> extends Vector<E> {}
Stack繼承自Vector,實現一個後進先出的堆棧。Stack提供5個額外的方法使得Vector得以被當作堆棧使用。基本的push和pop方法,還有peek方法得到棧頂的元素,empty方法測試堆棧是否為空白,search方法檢測一個元素在堆棧中的位置。Stack剛建立後是空棧。
Set介面
Set定義如下:
public interface Set<E> extends Collection<E> {}
Set是一個繼承於Collection的介面,Set是一種不包括重複元素的Collection。它維持它自己的內部排序,所以隨機訪問沒有任何意義。與List一樣,它同樣運行null的存在但是僅有一個。由於Set介面的特殊性,所有傳入Set集合中的元素都必須不同,
關於API方面。Set的API和Collection完全一樣。
實現了Set介面的集合有:HashSet、TreeSet、LinkedHashSet、EnumSet。
HashSet
HashSet定義如下:
public class HashSet<E> extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
HashSet堪稱查詢速度最快的集合,因為其內部是以HashCode來實現的。集合元素可以是null,但只能放入一個null。它內部元素的順序是由雜湊碼來決定的,所以它不保證set的迭代順序;特別是它不保證該順序恒久不變。
TreeSet
TreeSet定義如下:
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
TreeSet是二叉樹實現的,基於TreeMap,產生一個總是處於排序狀態的set,內部以TreeMap來實現,不允許放入null值。它是使用元素的自然順序對元素進行排序,或者根據建立Set時提供的 Comparator 進行排序,具體取決於使用的構造方法。
LinkedHashSet
LinkedHashSet定義如下:
public class LinkedHashSet<E> extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable
LinkedHashSet集合約樣是根據元素的hashCode值來決定元素的儲存位置,但是它同時使用鏈表維護元素的次序。這樣使得元素看起 來像是以插入順序儲存的,也就是說,當遍曆該集合時候,LinkedHashSet將會以元素的添加順序訪問集合的元素。LinkedHashSet在迭代訪問Set中的全部元素時,效能比HashSet好,但是插入時效能稍微遜色於HashSet。
EnumSet
EnumSet定義如下:
public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
implements Cloneable, java.io.Serializable
EnumSet中所有值都必須是指定枚舉類型的值,它的元素也是有序的,以枚舉值在枚舉類的定義順序來決定集合元素的順序。EnumSet集合不允許加入null元素,否則會拋出NullPointerException異常。EnumSet類沒有暴露任何構造器來建立該類的執行個體,程式應該通過它提供的static方法來建立EnumSet對象,例如:
public static void main(String[] args) { //建立一個EnumSet空集合,指定其集合元素是season1的枚舉值EnumSet<MyEnum>eSet1 = EnumSet.noneOf(MyEnum.class); ////建立一個EnumSet集合,集合元素就是Season裡的全部枚舉值EnumSet<MyEnum>eSet2 = EnumSet.allOf(MyEnum.class);}enum MyEnum { BLACK, WHITE, RED, BLUR, GREEN, YELLOW }
來看一個例子感受一下儲存元素的區別:
static Collection fill(Collection<String> collection) {collection.add("rat");collection.add("cat");collection.add("dog");collection.add("dog");return collection;}public static void main(String[] args) {System.out.println(fill(new HashSet<String>()));System.out.println(fill(new TreeSet<>()));System.out.println(fill(new LinkedHashSet<>()));}
HashSet是雜湊表實現的,儲存順序並無意義。如果儲存順序很重要,那麼可以使用TreeSet,它按比較結果的升序儲存對象;或者使用LinkedHashSet,它按照被添加的順序儲存元素。當然它們都是線程不安全的。
//Result:[rat, cat, dog][cat, dog, rat][rat, cat, dog]
Map介面
Map與List、Set介面不同,它是由一系列索引值對組成的集合,提供了key到Value的映射。在Map中它保證了key與value之間的一一對應關係。也就是說一個key對應一個value,所以它不能存在相同的key值,當然value值可以相同。
實現map的集合有:HashMap、HashTable、TreeMap、WeakHashMap。
HashMap
HashMap定義如下:
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
以雜湊表資料結構實現,尋找對象時通過雜湊Function Compute其位置,它是為快速查詢而設計的,其內部定義了一個hash表數組(Entry[] table),元素會通過雜湊轉換函式將元素的雜湊地址轉換成數組中存放的索引,如果有衝突,則使用散列鏈表的形式將所有相同雜湊地址的元素串起來,可能通過查看HashMap.Entry的源碼它是一個單鏈表結構。
HashTable
HashTable的定義如下:
public class Hashtable<K,V> extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable
也是以雜湊表資料結構實現的,解決衝突時與HashMap也一樣也是採用了散列鏈表的形式。HashTable繼承Dictionary類,實現Map介面。其中Dictionary類是任何可將鍵映射到相應值的類(如 Hashtable)的抽象父類。每個鍵和每個值都是一個對象。在任何一個 Dictionary 對象中,每個鍵至多與一個值相關聯。Map是”key-value索引值對”介面。 HashTable採用”拉鏈法”實現雜湊表不過效能比HashMap要低。
TreeMap
TreeMap的定義如下:
public class TreeMap<K,V> extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
有序散列表,實現SortedMap介面,底層通過紅/黑樹狀結構實現。
WeakHashMap
WeakHashMap的定義如下:
public class WeakHashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>
談WeakHashMap前先看一下Java中的引用(強度依次遞減)
- 強引用:普遍對象聲明的引用,存在便不會GC
- 軟引用:有用但並非必須,發生記憶體溢出前,二次回收
- 弱引用:只能生存到下次GC之前,無論是否記憶體足夠
- 虛引用:唯一目的是在這個對象被GC時能收到一個系統通知
以弱鍵實現的基於雜湊表的Map。在 WeakHashMap 中,當某個鍵不再正常使用時,將自動移除其條目。更精確地說,對於一個給定的鍵,其映射的存在並不阻止記憶體回收行程對該鍵的丟棄,這就使該鍵成為可終止的,被終止,然後被回收。丟棄某個鍵時,其條目從映射中有效地移除,因此,該類的行為與其他的 Map 實現有所不同。null值和null鍵都被支援。該類具有與HashMap類相似的效能特徵,並具有相同的效能參數初始容量和載入因子。像大多數集合類一樣,該類是不同步的。
Iterator
Iterator定義如下:
public interface Iterator<E> {}
Iterator是一個介面,它是集合的迭代器。集合可以通過Iterator去遍曆集合中的元素。Iterator提供的API介面,包括:是否存在下一個元素、擷取下一個元素、刪除當前元素。
注意:Iterator遍曆Collection時,是fail-fast機制的。即,當某一個線程A通過iterator去遍曆某集合的過程中,若該集合的內容被其他線程所改變了;那麼線程A訪問集合時,就會拋出ConcurrentModificationException異常,產生fail-fast事件。關於fail-fast的詳細內容,我們會在後面專門進行說明。
Iterator的API:
abstract boolean hasNext()abstract E next()abstract void remove()
最後用一張圖總結一下大體架構,後面會開始具體分析
連結:http://alexyyek.github.io/2015/04/06/Collection/
Java容器類總結