HashMap中的元素的特點:
HashMap中的所有key之間是不可重復的、無序的。所有的key構成一個Set集合。
HashMap中的所有的value彼此之間是可重復的、無序的。所有的value構成一個Collection集合。
HashMap中的一對key-value,就構成了一個entry。Map中的entry是不可重復的、無序的。所有的entry就構成了一個Set集合。
HashMap的源碼剖析:
jdk7:
HashMap < String , Integer > map = new HashMap<>(); //①
map.put("AA",78);//②
①:創建對象的過程中,底層會初始化數組,長度為16,即:Entry[ ] table = new Entry[16];
②:“AA”和78封裝到一個Entry對象中,將此對象添加到table數組中。
添加的過程:
將(key1,value1)添加到當前map中:首先,需要調用key1所在類的hashCode( )方法,計算key1對應的哈希值1,此哈希值1經過某種算法(hash( ))之后,得到哈希值2。哈希值2再經過某種算法(indexFor( ))之后,就確定了其在數組table的索引位置i。????????·如果此索引位置i的數組位置上沒有元素,則(key1,value1)添加成功。——情況①????????·如果此索引位置i的數組位置上有元素(若為key2),則需要繼續比較key1和key2的哈希值2。-->哈希沖突。?? ?????????????????·如果key1的哈希值與key2的哈希值不相同,則(key1,value1)也添加成功。——情況②· 如果key1的哈希值與key2的哈希值相同,則需要則需要繼續判斷key1和key2的equals( )的返回值。要調用key1所在類的equals( )方法,將key2作為參數傳入。?? ??? ?? ? ????????????????????????·如果調用equals( )方法,返回false:則(key1,value1)添加成功。——情況③?? ??? ?? ????????????????? ????????·如果調用equals( )方法,返回true:則認為key1和key2是相同的。默認情況下,value1替換原有的value2.
添加成功的情況:
情況①:直接將(key1,value1)存放到數組的索引i的位置
情況②與情況③:(key1,value1)元素與現有的(key2,value2)構成單向鏈表結構,(key1,value1)指向(key2,value2),jdk7中即頭插法。
如果滿足以下情況,會擴容:
當元素的個數達到臨界值(數組長度*加載因子)時,就考慮擴容。默認的加載因子為0.75。默認擴容后為原來的兩倍。
如果put方法是添加操作,會返回null。如果put是修改操作,會返回原來位置上的value值。
jdk8中:
①在jdk8中,當創建了HashMap實例以后,底層并沒有初始化table數組。當首次添加(key,value)時,進行判斷,如果發現table尚未初始化,則對數組進行初始化。(懶漢式)②在jdk8中,HashMap底層定義了Node內部類(實現了Entry接口),替換了jdk7中的Entry內部類。即創建的數組是Node[ ]。③在jdk8中,出現哈希值沖突的情況,判斷相應的(key,value)可以添加到指定發生哈希沖突的索引上,采用的是原來的元素指向新的元素,即尾插法。④在jdk7中,底層采用的是數組+單向鏈表。在jdk8中,底層采用的是數組+單向鏈表+紅黑樹。
使用紅黑樹的情況(單向鏈表轉換為紅黑樹):如果數組索引i上的元素的個數達到8,并且數組的長度達到64時,就將此索引i位置上的多個元素改為使用紅黑樹進行存儲。(紅黑樹進行put( )/get( )/remove( )等操作的時間復雜度為O(log n)),比單向鏈表的復雜度O(n)的要更好,性能更高。
紅黑樹退化(單向鏈表轉換為單向鏈表)的情況:當使用紅黑樹的索引i上的元素個數低于6時,就會將紅黑樹結構退化為單向鏈表。
LinkedHashMap與HashMap的關系:
LinkedHashMap是HashMap的子類。
LinkedHashMap在HashMap使用數組+單向鏈表+紅黑樹的基礎上,增加了一對雙向鏈表,記錄添加(key,value)的先后順序。便于遍歷所有的key-value。
HashSet和LinkedHashSet:
Hash底層使用的是HashMap。
LinkedHashSet底層使用的是LinkedHashMap。
HashSet的元素的值存儲在底層的HashMap的key值中,而所有的key值對應的value值都是同一個Object對象,HashSet里用不上其value值。LinkedHashSet同理。