JAVA 集合 接口繼承關系和實現(xiàn),List,Set,Map(總結(jié))

一. JAVA 集合

1.接口繼承關系和實現(xiàn)

集合類存放于 Java.util 包中,主要有 3 種:set(集)、list(列表包含 Queue)和 map(映射)。

1. Collection:Collection 是集合 List、Set、Queue 的最基本的接口。

2. Iterator:迭代器,可以通過迭代器遍歷集合中的數(shù)據(jù)

3. Map:是映射表的基礎接口


image.png
image.png

二.List

Java 的 List 是非常常用的數(shù)據(jù)類型。List 是有序的 Collection。Java List 一共三個實現(xiàn)類:

分別是 ArrayList、Vector 和 LinkedList。

image.png

1. ArrayList(數(shù)組)

ArrayList 是最常用的 List 實現(xiàn)類,內(nèi)部是通過數(shù)組實現(xiàn)的,它允許對元素進行快速隨機訪問。數(shù)組的缺點是每個元素之間不能有間隔,當數(shù)組大小不滿足時需要增加存儲能力,就要將已經(jīng)有數(shù)組的數(shù)據(jù)復制到新的存儲空間中。當從 ArrayList 的中間位置插入或者刪除元素時,需要對數(shù)組進行復制、移動、代價比較高。因此,它適合隨機查找和遍歷,不適合插入和刪除。

2. Vector(數(shù)組實現(xiàn)、線程同步)

Vector 與 ArrayList 一樣,也是通過數(shù)組實現(xiàn)的,不同的是它支持線程的同步,即某一時刻只有一個線程能夠?qū)?Vector,避免多線程同時寫而引起的不一致性,但實現(xiàn)同步需要很高的花費,因此,訪問它比訪問 ArrayList 慢。

3. LinkList(鏈表)

LinkedList 是用鏈表結(jié)構(gòu)存儲數(shù)據(jù)的,很適合數(shù)據(jù)的動態(tài)插入和刪除,隨機訪問和遍歷速度比較慢。另外,他還提供了 List 接口中沒有定義的方法,專門用于操作表頭和表尾元素,可以當作堆棧、隊列和雙向隊列使用。13/04/2018 Page 48 of 283

三.Set

Set 注重獨一無二的性質(zhì),該體系集合用于存儲無序(存入和取出的順序不一定相同)元素,值不能重復。對象的相等性本質(zhì)是對象 hashCode 值(java 是依據(jù)對象的內(nèi)存地址計算出的此序號)判斷的,如果想要讓兩個不同的對象視為相等的,就必須覆蓋 Object 的 hashCode 方法和 equals 方法。

image.png

1. HashSet(Hash 表)

哈希表邊存放的是哈希值。HashSet 存儲元素的順序并不是按照存入時的順序(和 List 顯然不同) 而是按照哈希值來存的所以取數(shù)據(jù)也是按照哈希值取得。元素的哈希值是通過元素的hashcode 方法來獲取的, HashSet 首先判斷兩個元素的哈希值,如果哈希值一樣,接著會比較equals 方法 如果 equls 結(jié)果為 true ,HashSet 就視為同一個元素。如果 equals 為 false 就不是同一個元素。

哈希值相同 equals 為 false 的元素是怎么存儲呢,就是在同樣的哈希值下順延(可以認為哈希值相同的元素放在一個哈希桶中)。也就是哈希一樣的存一列。如圖 1 表示 hashCode 值不相同的情況;圖 2 表示 hashCode 值相同,但 equals 不相同的情況。

image.png

HashSet 通過 hashCode 值來確定元素在內(nèi)存中的位置。一個 hashCode 位置上可以存放多個元素。

2. TreeSet(二叉樹)

1. TreeSet()是使用二叉樹的原理對新 add()的對象按照指定的順序排序(升序、降序),每增加一個對象都會進行排序,將對象插入的二叉樹指定的位置。

2. Integer 和 String 對象都可以進行默認的 TreeSet 排序,而自定義類的對象是不可以的,自己定義的類必須實現(xiàn) Comparable 接口,并且覆寫相應的 compareTo()函數(shù),才可以正常使用。

3. 在覆寫 compare()函數(shù)時,要返回相應的值才能使 TreeSet 按照一定的規(guī)則來排序

4. 比較此對象與指定對象的順序。如果該對象小于、等于或大于指定對象,則分別返回負整數(shù)、零或正整數(shù)。

3. LinkHashSet(HashSet+LinkedHashMap)

對于 LinkedHashSet 而言,它繼承與 HashSet、又基于 LinkedHashMap 來實現(xiàn)的。LinkedHashSet 底層使用 LinkedHashMap 來保存所有元素,它繼承與 HashSet,其所有的方法操作上又與 HashSet 相同,因此 LinkedHashSet 的實現(xiàn)上非常簡單,只提供了四個構(gòu)造方法,并通過傳遞一個標識參數(shù),調(diào)用父類的構(gòu)造器,底層構(gòu)造一個 LinkedHashMap 來實現(xiàn),在相關操作上與父類 HashSet 的操作相同,直接調(diào)用父類 HashSet 的方法即可。

四.Map

image.png

1. HashMap(數(shù)組+鏈表+紅黑樹)

HashMap 根據(jù)鍵的 hashCode 值存儲數(shù)據(jù),大多數(shù)情況下可以直接定位到它的值,因而具有很快的訪問速度,但遍歷順序卻是不確定的。 HashMap 最多只允許一條記錄的鍵為 null,允許多條記錄的值為 null。HashMap 非線程安全,即任一時刻可以有多個線程同時寫 HashMap,可能會導致數(shù)據(jù)的不一致。如果需要滿足線程安全,可以用 Collections 的 synchronizedMap 方法使HashMap 具有線程安全的能力,或者使ConcurrentHashMap。我們用下面這張圖來介紹HashMap 的結(jié)構(gòu)。

(1). JAVA7 實現(xiàn)

image.png

大方向上,HashMap 里面是一個數(shù)組,然后數(shù)組中每個元素是一個單向鏈表。上圖中,每個綠色的實體是嵌套類 Entry 的實例,Entry 包含四個屬性:key, value, hash 值和用于單向鏈表的 next。

1. capacity:當前數(shù)組容量,始終保持 2^n,可以擴容,擴容后數(shù)組大小為當前的 2 倍。

2. loadFactor:負載因子,默認為 0.75。13/04/2018 Page 51 of 283

3. threshold:擴容的閾值,等于 capacity * loadFactor

(2). JAVA8 實現(xiàn)

Java8 對 HashMap 進行了一些修改,最大的不同就是利用了紅黑樹,所以其由 數(shù)組+鏈表+紅黑樹 組成。

根據(jù) Java7 HashMap 的介紹,我們知道,查找的時候,根據(jù) hash 值我們能夠快速定位到數(shù)組的具體下標,但是之后的話,需要順著鏈表一個個比較下去才能找到我們需要的,時間復雜度取決于鏈表的長度,為 O(n)。為了降低這部分的開銷,在 Java8 中,當鏈表中的元素超過了 8 個以后,會將鏈表轉(zhuǎn)換為紅黑樹,在這些位置進行查找的時候可以降低時間復雜度為 O(logN)。

image.png

2. ConcurrentHashMap

(1). Segment 段

ConcurrentHashMap 和 HashMap 思路是差不多的,但是因為它支持并發(fā)操作,所以要復雜一些。整個 ConcurrentHashMap 由一個個 Segment 組成,Segment 代表”部分“或”一段“的意思,所以很多地方都會將其描述為分段鎖。注意,行文中,我很多地方用了“槽”來代表一個segment。

(2). 線程安全(Segment 繼承 ReentrantLock 加鎖)

簡單理解就是,ConcurrentHashMap 是一個 Segment 數(shù)組,Segment 通過繼承ReentrantLock 來進行加鎖,所以每次需要加鎖的操作鎖住的是一個 segment,這樣只要保證每個 Segment 是線程安全的,也就實現(xiàn)了全局的線程安全。

image.png

(3). 并行度(默認 16)

concurrencyLevel:并行級別、并發(fā)數(shù)、Segment 數(shù),怎么翻譯不重要,理解它。默認是 16,也就是說 ConcurrentHashMap 有 16 個 Segments,所以理論上,這個時候,最多可以同時支持 16 個線程并發(fā)寫,只要它們的操作分別分布在不同的 Segment 上。這個值可以在初始化的時候設置為其他值,但是一旦初始化以后,它是不可以擴容的。再具體到每個 Segment 內(nèi)部,其實每個 Segment 很像之前介紹的 HashMap,不過它要保證線程安全,所以處理起來要麻煩些。

(4). Java8 實現(xiàn) (引入了紅黑樹)

Java8 對 ConcurrentHashMap 進行了比較大的改動,Java8 也引入了紅黑樹。13/04/2018 Page 53 of 283

3. HashTable(線程安全)

Hashtable 是遺留類,很多映射的常用功能與 HashMap 類似,不同的是它承自 Dictionary 類,并且是線程安全的,任一時間只有一個線程能寫 Hashtable,并發(fā)性不如 ConcurrentHashMap,因為 ConcurrentHashMap 引入了分段鎖。Hashtable 不建議在新代碼中使用,不需要線程安全的場合可以用 HashMap 替換,需要線程安全的場合可以用 ConcurrentHashMap 替換。

4. TreeMap(可排序)

TreeMap 實現(xiàn) SortedMap 接口,能夠把它保存的記錄根據(jù)鍵排序,默認是按鍵值的升序排序,也可以指定排序的比較器,當用 Iterator 遍歷 TreeMap 時,得到的記錄是排過序的。如果使用排序的映射,建議使用 TreeMap。在使用 TreeMap 時,key 必須實現(xiàn) Comparable 接口或者在構(gòu)造 TreeMap 傳入自定義的Comparator,否則會在運行時拋出 java.lang.ClassCastException 類型的異常。

5. LinkHashMap(記錄插入順序)

LinkedHashMap 是 HashMap 的一個子類,保存了記錄的插入順序,在用 Iterator 遍歷

LinkedHashMap 時,先得到的記錄肯定是先插入的,也可以在構(gòu)造時帶參數(shù),按照訪問次序排序。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容