哈希表定義:根據設定的hash函數和處理衝突的方式(開放定址、公共溢出區、鏈地址、重哈希...)將一組關鍵字映射到一個有限的連續的地址集上(即bucket數組或桶數組),並以關鍵字在地址集中的「像」做爲記錄在表中的存儲位置,這種表稱爲hash表;這一映射過程稱爲散列,所得存儲位置稱爲哈希地址或散列地址。數組
HashMap實現了Map接口,繼承AbstractMap。其中Map接口定義了鍵映射到值的規則,而AbstractMap類提供 Map 接口的骨幹實現,以最大限度地減小實現此接口所需的工做。安全
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
HashMap提供了三個構造函數:數據結構
HashMap():構造一個具備默認初始容量 (16) 和默認加載因子 (0.75) 的空 HashMap。函數
HashMap(int initialCapacity):構造一個帶指定初始容量和默認加載因子 (0.75) 的空 HashMap。性能
HashMap(int initialCapacity, float loadFactor):構造一個帶指定初始容量和加載因子的空 HashMap。spa
容量表示哈希表中桶的數量,初始容量是建立哈希表時的容量; 裝載因子:loadfactor = 表中填入的記錄數/哈希表的長度線程
因此loadfactor標誌着哈希表的裝滿程度,直觀的看,裝載因子越小,發生衝突的機率越小(由於桶中還沒裝幾個數據,就須要擴容),也就是查找性能越好,但同時浪費的空間就變大。相反,裝載因子越大,發生衝突的機率越大(等到桶快填滿時才能擴容,好比,採用鏈表法處理衝突,在此種狀況下,會致使鏈表過長),查找性能越差,同時浪費的空間會減小。
咱們知道在Java中最經常使用的兩種結構是數組和模擬指針(引用),幾乎全部的數據結構均可以利用這兩種來組合實現,HashMap也是如此。實際上HashMap是一個「鏈表散列」(數組和鏈表的結合體)。指針
可見,HashMap底層實現仍是數組(橫行),只是數組的每一項(縱列)都是一條鏈。Entry爲HashMap的內部類,它包含了鍵key、值value、下一個節點next,以及hash值,這是很是重要的,正是因爲Entry才構成了table數組的項爲鏈表。code
*1.HashMap的默認大小爲16,即桶數組的默認長度爲16;
2.HashMap的默認裝載因子是0.75;
3.HashMap內部的桶數組存儲的是Entry對象,也就是鍵值對對象。
4.構造器支持指定初始容量和裝載因子,爲避免數組擴容帶來的性能問題,建議根據需求指定初始容量。裝載因子儘可能不要修改,0.75是個比較靠譜的值。
5.桶數組的長度始終是2的整數次方(大於等於指定的初始容量),這樣作能夠減小衝突機率,提升查找效率。(能夠從indexfor函數中看出,h&(length-1),若length爲奇數,length-1爲偶數那麼h&(length-1)結果的最後一位必然爲0,也就是說全部鍵都被散列到數組的偶數下標位置,這樣會浪費近一半空間。另外,length爲2的整數次方也保證了h&(length-1)與h%length等效).
6.HashMap接受null鍵;
7.HashMap不容許鍵重複,可是值是能夠重複的。若鍵重複,那麼新值會覆蓋舊值。
8.HashMap經過鏈表法解決衝突問題,每一個Entry都有一個next指針指向下一個Entry,衝突元素(不是鍵相同,而是hash值相同)會構成一個鏈表。而且最新插入的鍵值對始終位於鏈表首部。
9.當容量超過閾值(threshold)時,會發生擴容,擴容後的數組是原數組的兩倍。擴容操做須要開闢新數組,並對原數組中全部鍵值對從新散列,很是耗時。咱們應該儘可能避免HashMap擴容。
10.HashMap非線程安全。*對象