數組和鏈表都是存儲一個對象,HashMap 存儲數據是以 一對數據來存儲,即鍵值對【key(對象)---->value(對象)】。算法
JDK1.8版本以前,HashMap的實現: 數組 + 鏈表;數組
JDK1.8版本以後,HashMap的實現: 數組 + 鏈表 / 二叉樹(紅黒樹);安全
數組的默認大小是16,加載因子【DEFAULT_LOAD_FACTOR】默認值是0.75f,表示當數組容量達到75%,數組會被從新擴充。數組的最大容量是整數最大值的一半。數據結構
HashMap存儲數據結構中鏈表與二叉樹的轉化條件: 是鍵值對的總數大於64,且性能
a.在擴容時,當哈希表中數組同一個位置的鏈表長度大於8時(閥值),那麼會把鏈表轉換成紅黑樹,來提升查詢效率;spa
b.在擴容時,當哈希表中數組同一個位置的鏈表長度小於6時(閥值),那麼會把紅黑樹轉換成鏈表,來提升查詢效率。線程
閥值爲何是8 和 6? (防抖)減小鏈表與二叉樹之間的轉換頻率,避免影響性能。對象
哈希表:這個是由於存儲數據的方式被稱爲哈希(算法),Object類中hashCode方法是一個本地方法:表示此方法的具體實現是由 C、C++來實現的,哈希值()。內存
同一個對象,咱們要保證在運行期hashCode值是相同的,若是不一樣那麼此對象在哈希表中會有內存泄露問題。ci
內存泄露:因爲對象在運行過程當中,hashCode不一樣,致使該對象在哈希表中沒法找到。
哈希表存儲數據的算法:經過計算key對象的hashCode值,來確認key對象在哈希表數組中的存儲位置,目的是爲了能夠經過計算hash值快速的查找對象。同一個對象,hashCode值相同,不一樣的對象,hashCode可能相同,由於整數是有限的。
使用hashCode計算對象的hash值:return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16)。
怎麼擴容?初始化大小?
a.在第一次put數據的時候初始化;
b.在put方法中實現,擴容算法是 oldCap << 1 表示乘於2;
c.每次擴容哈希表,會致使全部已存儲的對象從新計算哈希值,存儲到新的哈希表中(從新散列)。因此在hashMap中,對象所在的位置不保證永遠不變(無序),從新散列會致使從新計算全部對象,消耗性能,在可預知的狀況下,散列次數越少越好。
HashMap的優勢與缺點?
優勢:取值快,數據量越大越明顯;
缺點:線程不安全,避免頻繁散列(rehash)。合理的使用new HashMap<>(initialCapacity);初始容量,來減小散列。