自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

HashMap中傻傻分不清楚的那些概念

開(kāi)發(fā) 開(kāi)發(fā)工具
很多人在通過(guò)閱讀源碼的方式學(xué)習(xí)Java,這是個(gè)很好的方式。而JDK的源碼自然是首選。在JDK的眾多類(lèi)中,我覺(jué)得HashMap及其相關(guān)的類(lèi)是設(shè)計(jì)的比較好的。很多人讀過(guò)HashMap的代碼,不知道你們有沒(méi)有和我一樣,覺(jué)得HashMap中關(guān)于容量相關(guān)的參數(shù)定義的太多了,傻傻分不清楚。

很多人在通過(guò)閱讀源碼的方式學(xué)習(xí)Java,這是個(gè)很好的方式。而JDK的源碼自然是***。在JDK的眾多類(lèi)中,我覺(jué)得HashMap及其相關(guān)的類(lèi)是設(shè)計(jì)的比較好的。很多人讀過(guò)HashMap的代碼,不知道你們有沒(méi)有和我一樣,覺(jué)得HashMap中關(guān)于容量相關(guān)的參數(shù)定義的太多了,傻傻分不清楚。

[[230071]]

其實(shí),這篇文章介紹的內(nèi)容比較簡(jiǎn)單,只要認(rèn)真的看看HashMap的原理還是可以理解的,單獨(dú)寫(xiě)一篇文章的原因是因?yàn)槲液竺孢€有幾篇關(guān)于HashMap源碼分析的文章,這些概念不熟悉的話(huà)閱讀后面的文章會(huì)很吃力。

HashMap中重要的成員變量

先來(lái)看一下,HashMap中都定義了哪些成員變量。

上面是一張HashMap中主要的成員變量的圖,其中有一個(gè)是我們本文主要關(guān)注的: size、loadFactor、threshold、DEFAULT_LOAD_FACTOR和DEFAULT_INITIAL_CAPACITY。

我們先來(lái)簡(jiǎn)單解釋一下這些參數(shù)的含義,然后再分析他們的作用。

HashMap類(lèi)中有以下主要成員變量:

  • transient int size; 

記錄了Map中KV對(duì)的個(gè)數(shù)

  • loadFactor 

裝載印子,用來(lái)衡量HashMap滿(mǎn)的程度。loadFactor的默認(rèn)值為0.75f(static final float DEFAULT_LOAD_FACTOR = 0.75f;)。

  • int threshold; 

臨界值,當(dāng)實(shí)際KV個(gè)數(shù)超過(guò)threshold時(shí),HashMap會(huì)將容量擴(kuò)容,threshold=容量*加載因子

  • 除了以上這些重要成員變量外,HashMap中還有一個(gè)和他們緊密相關(guān)的概念:capacity 

容量,如果不指定,默認(rèn)容量是16(static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;)

可能看完了你還是有點(diǎn)蒙,size和capacity之間有啥關(guān)系?為啥要定義這兩個(gè)變量。loadFactor和threshold又是干啥的?

size 和 capacity

HashMap中的size和capacity之間的區(qū)別其實(shí)解釋起來(lái)也挺簡(jiǎn)單的。我們知道,HashMap就像一個(gè)“桶”,那么capacity就是這個(gè)桶“當(dāng)前”最多可以裝多少元素,而size表示這個(gè)桶已經(jīng)裝了多少元素。來(lái)看下以下代碼:

  1. Map<String, String> map = new HashMap<String, String>(); 
  2. map.put("hollis""hollischuang"); 
  3.  
  4. Class<?> mapType = map.getClass(); 
  5. Method capacity = mapType.getDeclaredMethod("capacity"); 
  6. capacity.setAccessible(true); 
  7. System.out.println("capacity : " + capacity.invoke(map)); 
  8.  
  9. Field size = mapType.getDeclaredField("size"); 
  10. size.setAccessible(true); 
  11. System.out.println("size : " + size.get(map)); 

我們定義了一個(gè)新的HashMap,并想其中put了一個(gè)元素,然后通過(guò)反射的方式打印capacity和size。輸出結(jié)果為:capacity : 16、size : 1

默認(rèn)情況下,一個(gè)HashMap的容量(capacity)是16,設(shè)計(jì)成16的好處我在《全網(wǎng)把Map中的hash()分析的最透徹的文章,別無(wú)二家?!分幸埠?jiǎn)單介紹過(guò),主要是可以使用按位與替代取模來(lái)提升hash的效率。

為什么我剛剛說(shuō)capacity就是這個(gè)桶“當(dāng)前”最多可以裝多少元素呢?當(dāng)前怎么理解呢。其實(shí),HashMap是具有擴(kuò)容機(jī)制的。在一個(gè)HashMap***次初始化的時(shí)候,默認(rèn)情況下他的容量是16,當(dāng)達(dá)到擴(kuò)容條件的時(shí)候,就需要進(jìn)行擴(kuò)容了,會(huì)從16擴(kuò)容成32。

我們知道,HashMap的重載的構(gòu)造函數(shù)中,有一個(gè)是支持傳入initialCapacity的,那么我們嘗試著設(shè)置一下,看結(jié)果如何。

  1. Map<String, String> map = new HashMap<String, String>(1); 
  2. map.put("hahaha""hollischuang"); 
  3.  
  4. Class<?> mapType = map.getClass(); 
  5. Method capacity = mapType.getDeclaredMethod("capacity"); 
  6. capacity.setAccessible(true); 
  7. System.out.println("capacity : " + capacity.invoke(map)); 
  8.  
  9. Map<String, String> map = new HashMap<String, String>(7); 
  10. map.put("hahaha""hollischuang"); 
  11.  
  12. Class<?> mapType = map.getClass(); 
  13. Method capacity = mapType.getDeclaredMethod("capacity"); 
  14. capacity.setAccessible(true); 
  15. System.out.println("capacity : " + capacity.invoke(map)); 
  16.  
  17.  
  18. Map<String, String> map = new HashMap<String, String>(9); 
  19. map.put("hahaha""hollischuang"); 
  20.  
  21. Class<?> mapType = map.getClass(); 
  22. Method capacity = mapType.getDeclaredMethod("capacity"); 
  23. capacity.setAccessible(true); 
  24. System.out.println("capacity : " + capacity.invoke(map)); 

分別執(zhí)行以上3段代碼,分別輸出:capacity : 2、capacity : 8、capacity : 16。

也就是說(shuō),默認(rèn)情況下HashMap的容量是16,但是,如果用戶(hù)通過(guò)構(gòu)造函數(shù)指定了一個(gè)數(shù)字作為容量,那么Hash會(huì)選擇大于該數(shù)字的***個(gè)2的冪作為容量。(1->2、7->8、9->16)

這里有一個(gè)小建議:在初始化HashMap的時(shí)候,應(yīng)該盡量指定其大小。尤其是當(dāng)你已知map中存放的元素個(gè)數(shù)時(shí)。(《阿里巴巴Java開(kāi)發(fā)規(guī)約》)

loadFactor 和 threshold

前面我們提到過(guò),HashMap有擴(kuò)容機(jī)制,就是當(dāng)達(dá)到擴(kuò)容條件時(shí)會(huì)進(jìn)行擴(kuò)容,從16擴(kuò)容到32、64、128...

那么,這個(gè)擴(kuò)容條件指的是什么呢?

其實(shí),HashMap的擴(kuò)容條件就是當(dāng)HashMap中的元素個(gè)數(shù)(size)超過(guò)臨界值(threshold)時(shí)就會(huì)自動(dòng)擴(kuò)容。

在HashMap中,threshold = loadFactor * capacity。

loadFactor是裝載因子,表示HashMap滿(mǎn)的程度,默認(rèn)值為0.75f,設(shè)置成0.75有一個(gè)好處,那就是0.75正好是3/4,而capacity又是2的冪。所以,兩個(gè)數(shù)的乘積都是整數(shù)(capacity為2也同樣)。

對(duì)于一個(gè)默認(rèn)的HashMap來(lái)說(shuō),默認(rèn)情況下,當(dāng)其size大于12(16*0.75)時(shí)就會(huì)觸發(fā)擴(kuò)容。

驗(yàn)證代碼如下:

  1. Map<String, String> map = new HashMap<>(); 
  2. map.put("hollis1""hollischuang"); 
  3. map.put("hollis2""hollischuang"); 
  4. map.put("hollis3""hollischuang"); 
  5. map.put("hollis4""hollischuang"); 
  6. map.put("hollis5""hollischuang"); 
  7. map.put("hollis6""hollischuang"); 
  8. map.put("hollis7""hollischuang"); 
  9. map.put("hollis8""hollischuang"); 
  10. map.put("hollis9""hollischuang"); 
  11. map.put("hollis10""hollischuang"); 
  12. map.put("hollis11""hollischuang"); 
  13. map.put("hollis12""hollischuang"); 
  14. Class<?> mapType = map.getClass(); 
  15.  
  16. Method capacity = mapType.getDeclaredMethod("capacity"); 
  17. capacity.setAccessible(true); 
  18. System.out.println("capacity : " + capacity.invoke(map)); 
  19.  
  20. Field size = mapType.getDeclaredField("size"); 
  21. size.setAccessible(true); 
  22. System.out.println("size : " + size.get(map)); 
  23.  
  24. Field threshold = mapType.getDeclaredField("threshold"); 
  25. threshold.setAccessible(true); 
  26. System.out.println("threshold : " + threshold.get(map)); 
  27.  
  28. Field loadFactor = mapType.getDeclaredField("loadFactor"); 
  29. loadFactor.setAccessible(true); 
  30. System.out.println("loadFactor : " + loadFactor.get(map)); 
  31.  
  32. map.put("hollis13""hollischuang"); 
  33. Method capacity = mapType.getDeclaredMethod("capacity"); 
  34. capacity.setAccessible(true); 
  35. System.out.println("capacity : " + capacity.invoke(map)); 
  36.  
  37. Field size = mapType.getDeclaredField("size"); 
  38. size.setAccessible(true); 
  39. System.out.println("size : " + size.get(map)); 
  40.  
  41. Field threshold = mapType.getDeclaredField("threshold"); 
  42. threshold.setAccessible(true); 
  43. System.out.println("threshold : " + threshold.get(map)); 
  44.  
  45. Field loadFactor = mapType.getDeclaredField("loadFactor"); 
  46. loadFactor.setAccessible(true); 
  47. System.out.println("loadFactor : " + loadFactor.get(map)); 

輸出結(jié)果:

  1. capacity : 16 
  2. size : 12 
  3. threshold : 12 
  4. loadFactor : 0.75 
  5.  
  6. capacity : 32 
  7. size : 13 
  8. threshold : 24 
  9. loadFactor : 0.75 

當(dāng)HashMap中的元素個(gè)數(shù)達(dá)到13的時(shí)候,capacity就從16擴(kuò)容到32了。

HashMap中還提供了一個(gè)支持傳入initialCapacity,loadFactor兩個(gè)參數(shù)的方法,來(lái)初始化容量和裝載因子。不過(guò),一般不建議修改loadFactor的值。

總結(jié)

HashMap中size表示當(dāng)前共有多少個(gè)KV對(duì),capacity表示當(dāng)前HashMap的容量是多少,默認(rèn)值是16,每次擴(kuò)容都是成倍的。loadFactor是裝載因子,當(dāng)Map中元素個(gè)數(shù)超過(guò)loadFactor* capacity的值時(shí),會(huì)觸發(fā)擴(kuò)容。loadFactor* capacity可以用threshold表示。

【本文是51CTO專(zhuān)欄作者Hollis的原創(chuàng)文章,作者微信公眾號(hào)Hollis(ID:hollischuang)】

戳這里,看該作者更多好文

責(zé)任編輯:武曉燕 來(lái)源: 51CTO專(zhuān)欄
相關(guān)推薦

2021-03-10 08:56:37

Zookeeper

2021-07-27 07:31:16

JavaArrayList數(shù)組

2022-05-15 21:52:04

typeTypeScriptinterface

2024-02-29 09:08:56

Encoding算法加密

2021-02-14 22:33:23

Java字符字段

2020-10-30 08:20:04

SD卡TF卡存儲(chǔ)

2018-12-17 12:30:05

Kubernetes存儲(chǔ)存儲(chǔ)卷

2020-03-03 17:35:09

Full GCMinor

2023-02-27 15:46:19

數(shù)據(jù)元元數(shù)據(jù)

2023-09-03 21:18:07

Python編程語(yǔ)言

2021-11-09 06:01:35

前端JITAOT

2021-02-08 23:47:51

文件存儲(chǔ)塊存儲(chǔ)對(duì)象存儲(chǔ)

2016-11-04 12:51:46

Unix網(wǎng)絡(luò)IO 模型

2022-02-25 09:14:33

類(lèi)變量共享實(shí)例變量

2024-11-04 00:00:03

viewportDOMSPA

2021-01-13 08:10:26

接口IEnumeratorIEnumerable

2020-11-11 07:32:18

MySQL InnoDB 存儲(chǔ)

2023-04-11 15:57:49

JavaScriptCSSHTML

2019-11-21 14:22:12

WiFiWLAN區(qū)別

2021-06-07 09:20:56

Javascript運(yùn)算符開(kāi)發(fā)
點(diǎn)贊
收藏

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