成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

面試突擊:說一下HashMap底層實(shí)現(xiàn)?及元素添加流程?

開發(fā) 前端
HashMap 是使用頻率最高的數(shù)據(jù)類型之一,同時也是面試必問的問題之一,尤其是它的底層實(shí)現(xiàn)原理,既是常見的面試題又是理解 HashMap 的基石,所以重要程度不言而喻。

HashMap 是使用頻率最高的數(shù)據(jù)類型之一,同時也是面試必問的問題之一,尤其是它的底層實(shí)現(xiàn)原理,既是常見的面試題又是理解 HashMap 的基石,所以重要程度不言而喻。

HashMap 底層實(shí)現(xiàn)

HashMap 在 JDK 1.7 和 JDK 1.8 的底層實(shí)現(xiàn)是不一樣的,在 JDK 1.7 中,HashMap 使用的是數(shù)組 + 鏈表實(shí)現(xiàn)的,而 JDK 1.8 中使用的是數(shù)組 + 鏈表或紅黑樹實(shí)現(xiàn)的。HashMap 在 JDK 1.7 中的實(shí)現(xiàn)如下圖所示:

HashMap 在 JDK 1.8 中的實(shí)現(xiàn)如下圖所示:

我們本文重點(diǎn)來學(xué)習(xí)主流版本 JDK 1.8 中的 HashMap。HashMap 中每個元素稱之為一個哈希桶(bucket),哈希桶包含的內(nèi)容有 4 個:

  • hash 值
  • key
  • value
  • next(下一個節(jié)點(diǎn))

HashMap 插入流程

HashMap 元素新增的實(shí)現(xiàn)源碼如下(下文源碼都是基于主流版本 JDK 1.8):

  1. public V put(K key, V value) { 
  2.     // 對 key 進(jìn)行哈希操作 
  3.     return putVal(hash(key), key, value, falsetrue); 
  4. final V putVal(int hash, K key, V value, boolean onlyIfAbsent, 
  5.                boolean evict) { 
  6.     Node<K,V>[] tab; Node<K,V> p; int n, i; 
  7.     // 哈希表為空則創(chuàng)建表 
  8.     if ((tab = table) == null || (n = tab.length) == 0) 
  9.         n = (tab = resize()).length; 
  10.     // 根據(jù) key 的哈希值計算出要插入的數(shù)組索引 i 
  11.     if ((p = tab[i = (n - 1) & hash]) == null
  12.         // 如果 table[i] 等于 null,則直接插入 
  13.         tab[i] = newNode(hash, key, value, null); 
  14.     else { 
  15.         Node<K,V> e; K k; 
  16.         // 如果 key 已經(jīng)存在了,直接覆蓋 value 
  17.         if (p.hash == hash && 
  18.             ((k = p.key) == key || (key != null && key.equals(k)))) 
  19.             e = p; 
  20.         // 如果 key 不存在,判斷是否為紅黑樹 
  21.         else if (p instanceof TreeNode) 
  22.             // 紅黑樹直接插入鍵值對 
  23.             e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); 
  24.         else { 
  25.             // 為鏈表結(jié)構(gòu),循環(huán)準(zhǔn)備插入 
  26.             for (int binCount = 0; ; ++binCount) { 
  27.                 // 下一個元素為空時 
  28.                 if ((e = p.next) == null) { 
  29.                     p.next = newNode(hash, key, value, null); 
  30.                     // 轉(zhuǎn)換為紅黑樹進(jìn)行處理 
  31.                     if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st 
  32.                         treeifyBin(tab, hash); 
  33.                     break; 
  34.                 } 
  35.                 //  key 已經(jīng)存在直接覆蓋 value 
  36.                 if (e.hash == hash && 
  37.                     ((k = e.key) == key || (key != null && key.equals(k)))) 
  38.                     break; 
  39.                 p = e; 
  40.             } 
  41.         } 
  42.         if (e != null) { // existing mapping for key 
  43.             V oldValue = e.value; 
  44.             if (!onlyIfAbsent || oldValue == null
  45.                 e.value = value; 
  46.             afterNodeAccess(e); 
  47.             return oldValue; 
  48.         } 
  49.     } 
  50.     ++modCount; 
  51.     // 超過最大容量,擴(kuò)容 
  52.     if (++size > threshold) 
  53.         resize(); 
  54.     afterNodeInsertion(evict); 
  55.     return null

上述的源碼都添加了相應(yīng)的代碼注釋,簡單來說 HashMap 的元素添加流程是,先將 key 值進(jìn)行 hash 得到哈希值,根據(jù)哈希值得到元素位置,判斷元素位置是否為空,如果為空直接插入,不為空判斷是否為紅黑樹,如果是紅黑樹則直接插入,否則判斷鏈表是否大于 8,且數(shù)組長度大于 64,如果滿足這兩個條件則把鏈表轉(zhuǎn)成紅黑樹,然后插入元素,如果不滿足這兩個條件中的任意一個,則遍歷鏈表進(jìn)行插入,它的執(zhí)行流程如下圖所示:

為什么要將鏈表轉(zhuǎn)紅黑樹?

JDK 1.8 中引入了新的數(shù)據(jù)結(jié)構(gòu)紅黑樹來實(shí)現(xiàn) HashMap,主要是出于性能的考量。因?yàn)殒湵沓^一定長度之后查詢效率就會很低,它的時間復(fù)雜度是 O(n),而紅黑樹的時間復(fù)雜度是 O(logn),因此引入紅黑樹可以加快 HashMap 在數(shù)據(jù)量比較大的情況下的查詢效率。

哈希算法實(shí)現(xiàn)

HashMap 的哈希算法實(shí)現(xiàn)源碼如下:

  1. static final int hash(Object key) { 
  2.     int h; 
  3.     return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); 

其中,key.hashCode() 是 Java 中自帶的 hashCode() 方法,返回一個 int 類型的散列值,后面 hashCode 再右移 16 位,正好是 32bit 的一半,與自己本身做異或操作(相同為 0,不同為 1),主要是為了混合哈希值的高位和低位,增加低位的隨機(jī)性,這樣就實(shí)現(xiàn)了 HashMap 的哈希算法。

總結(jié)

HashMap 在 JDK 1.7 時,使用的是數(shù)組 + 鏈表實(shí)現(xiàn)的,而在 JDK 1.8 時,使用的是數(shù)組 + 鏈表或紅黑樹的方式來實(shí)現(xiàn)的,JDK 1.8 之所以引入紅黑樹主要是出于性能方面的考慮。HashMap 在插入時,會判斷當(dāng)前鏈表的長度是否大于 8 且數(shù)組的長度大于 64,如果滿足這兩個條件就會把鏈表轉(zhuǎn)成紅黑樹再進(jìn)行插入,否則就是遍歷鏈表插入。

參考文檔:https://tech.meituan.com/2016/06/24/java-hashmap.html

本文轉(zhuǎn)載自微信公眾號「Java面試真題解析」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系Java面試真題解析公眾號。

 

責(zé)任編輯:武曉燕 來源: Java面試真題解析
相關(guān)推薦

2022-06-29 11:01:05

MySQL事務(wù)隔離級別

2022-09-27 21:14:54

Spring事務(wù)傳播機(jī)制

2022-09-05 07:06:59

BeanSpring

2022-05-18 07:43:09

Exchange交換器JUC

2023-02-06 07:01:51

2022-02-17 08:02:08

線程Java生命周期

2022-03-09 07:35:24

線程池線程參數(shù)

2022-07-20 07:29:55

TCPIP協(xié)議

2023-11-29 08:00:53

JavaTreeMap底層

2022-04-13 14:43:05

JVM同步鎖Monitor 監(jiān)視

2024-02-27 15:23:48

RedLock算法Redis

2023-09-12 14:56:13

MyBatis緩存機(jī)制

2024-01-29 10:08:11

零拷貝Zero-copyCPU 拷貝

2025-03-10 07:05:07

2021-07-28 10:08:19

類加載代碼塊面試

2023-02-02 07:06:10

2022-06-07 12:03:33

Java內(nèi)存模型

2023-02-08 08:32:41

輪詢鎖

2023-02-18 13:34:14

Nacos健康檢查機(jī)制

2022-06-06 15:33:20

線程Java釋放鎖
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 毛片在线免费播放 | 欧美一级免费看 | 国产午夜视频 | 国产在线观看福利 | 亚洲午夜视频 | 国产电影一区二区在线观看 | 亚洲精品99| av在线免费观看网站 | 国产中文字幕av | 亚洲视频中文字幕 | 久久艹免费视频 | 在线看亚洲 | 欧美精品在线视频 | 中文字幕 国产 | 免费视频二区 | 成人av看片| 日韩一二三区视频 | 99reav| 免费看国产片在线观看 | 操久久久| 欧洲av在线 | 99精品国产一区二区青青牛奶 | 久久综合影院 | 午夜免费观看 | 国产精品久久久久久久久久三级 | 国产精品视频一二三 | 男女免费观看在线爽爽爽视频 | 国产精品久久久久久久久久久久冷 | 日韩精品一区二区三区在线观看 | 九九伦理片 | 色.com| 自拍第一页 | 超碰人人艹 | 久久久www成人免费无遮挡大片 | 网站黄色在线免费观看 | 伊人精品国产 | 一区二区三区四区在线视频 | 黄网站在线观看 | 99亚洲精品视频 | 中文字幕影院 | 伊人网综合 |