1. 程式人生 > 其它 >java集合:Collection和Map

java集合:Collection和Map

Collection

List和Set的區別:

(1)有序性:List保證按插入順序排序,set儲存和取出順序不一致

(2)唯一性:List可以重複,Set元素唯一

(3)獲取元素:List可以通過索引直接操作元素,Set不能根據索引獲取元素

HashSet底層資料結構採用雜湊表實現,元素無序且唯一,執行緒不安全,效率高,可以儲存null元素,元素的唯一性是靠所儲存元素型別是否重寫hashCode()和equals()方法來保證,如果沒有重寫這兩個方法,則無法保證元素的唯一性。

HashSet採用雜湊演算法,底層用陣列儲存資料,預設初始化容量為16,載入因子0.75.

LinkedHashSet底層採用連結串列和雜湊表共同實現,連結串列保證元素的順序和儲存順序一致,雜湊表保證了元素的唯一性,執行緒不安全,效率高。

TreeSet底層採用二叉樹(紅黑樹)來實現,元素唯一且已經排好序,不允許放null值,新增資料要求是同類的物件。

新增元素的過程,以HashSet為例:

向HashSet中新增元素a,首先呼叫元素a所在類的hashCode()方法,計算元素a的雜湊值,此雜湊值接著通過某種演算法計算出在HashSet底層陣列中的存放位置(索引位置),判斷陣列此位置上是否已經有元素:

    如果此位置上沒有其他元素,則元素a新增成功(情形1

    如果此位置上有其他元素b(或以連結串列形式存在的多個元素),則比較元素a與元素b的hash值:

      如果hash值不同,則元素a新增成功(情形2)

      如果hash值相同,進而需要呼叫元素a所在類的equlas()方法

        equals()返回true,元素a新增失敗

        equals()返回false,則元素a新增成功(情形3)

  對於情形2和3:元素a與已經存在指定索引位置上資料以連結串列的方式儲存

  jdk7:元素a放在陣列中,指向原來的元素

  jdk8:原來的元素在陣列中,指向a元素

Map

Map實現類結構

|----Map:雙列資料,儲存key-value對的資料 ----類似於高中的函式:y=f(x)

  |----HashMap:作為Map的主要實現類,執行緒不安全,效率高,儲存null的key和value。

    |----LinkedHashMap:保證在遍歷map元素時,可以按照新增的順序實現遍歷;

      原因是在原有的HashMap底層結構基礎上,新增一對指標,指向前一個和後一個元素。

      對於頻繁的遍歷操作,LinkedHasnMap執行效率高於HashMap。

  |----TreeMap:保證按照新增的key-value對進行排序,實現排序遍歷。此時根據key的自然排序或定製排序;底層使用紅黑樹。

  |----HashTable作為古老的實現類,執行緒安全,效率低,不能儲存null的key和value

    |----Properties:常用來處理配置檔案。key和value都是String型別

Map結構

Map中的key:無序的,不可重複的,使用Set儲存所有的key ----->key所在的類要重寫equals()和hashCode()方法(以HashMap為例)

Map中的value:無序的,可重複的,使用Collection儲存所有的Value ----->value所在的類要重寫equals()

一個鍵值對:key-value構成一個Entry物件

Map中的entry:無序的,不可重複的,使用Set儲存所有的entry。

HashMap的底層實現

以jdk7為例:

HashMap map = new HashMap()

在例項化以後,底層建立了長度是16的一維陣列Entry[] table.

map.put(key1,value1)

這可能執行過多次put),首先呼叫key1所在類的hashCode()計算key1雜湊值,此雜湊值經過某種演算法計算以後,得到在Entry陣列中的存在位置。

如果此位置上的資料為空,此時的key1-value1新增成功(情形1)

如果此位置上的資料不為空,意味著此位置上存在一個或多個數據(以連結串列形式存在),比較key1和已經存在的一個或多個數據的雜湊值:

     如果key1的雜湊值與已經存在的資料的雜湊值都不相同,此時key1-value1新增成功(情形2)

     如果key1的雜湊值和已經存在的某一個數據(key2-value2)的雜湊值相同,繼續比較:呼叫key1所在類的equals(key2)

        如果equals()返回false,此時key1-value1新增成功(情形3)

        如果equals()返回true,使用value1替換value2

補充:關於情形3和情形3:此時key1-value1和原來的資料以連結串列的方式儲存

在不斷的新增過程中,會涉及到擴容問題,預設擴容方式:擴容為原來容量的2倍,並將原來的資料複製過來。

jdk8相對於jdk7在底層實現方面的不同:

1. new HashMap():底層沒有建立一個長度為16的陣列

2. jdk8底層的陣列是: Node[] ,而非Entry[]

3. 首次呼叫put()方法時,底層建立長度為16的陣列

4. jdk7底層結構只有陣列+連結串列。jdk8中底層結構:陣列+連結串列+紅黑樹。

  當陣列的某一索引位置上的元素以連結串列形式存在的資料個數>8且當前陣列的長度>64時,此時此索引位置上的所有資料改為使用紅黑樹儲存