偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

作為Java開發(fā),知道HashMap底層存儲原理總不會害你

開發(fā) 后端
HasnMap是基于map接口實(shí)現(xiàn),元素以鍵值對的方式存儲,并且鍵和值都可以使用null,因?yàn)?key不允許重復(fù),因此只能有一個(gè)鍵為null。

概念

  • HasnMap是基于map接口實(shí)現(xiàn),元素以鍵值對的方式存儲,并且鍵和值都可以使用null,因?yàn)?key不允許重復(fù),因此只能有一個(gè)鍵為null
  • HaasnMap是 無序不重復(fù)的,而且HashMap是線程不安全 的
  • JDK7HashMap的數(shù)據(jù)結(jié)構(gòu)為:數(shù)組+鏈表
  • JDK8HashMap的數(shù)據(jù)結(jié)構(gòu)為:數(shù)組 + 鏈表 + 紅黑樹

存儲的優(yōu)點(diǎn)

  • 數(shù)組的特點(diǎn):查詢效率高,插入和刪除效率低
  • 鏈表的特點(diǎn):查詢效率 低,插入和刪除效率高
  • 在HasnMap底層使用數(shù)組加 (鏈表或紅黑樹) 的結(jié)構(gòu)完美的解決了數(shù)組和鏈表的問題,使的查詢和插入,刪除的效率都 很高
  • HashMap的散列表是懶加載機(jī)制,在第一次put的時(shí)候才會創(chuàng)建

HashMap存儲元素的過程

首先將k、v封裝到Node對象當(dāng)中(節(jié)點(diǎn))

調(diào)用k的hasnCode()方法取出hash值;通過hashcode值和數(shù)組長度取模得到元素存儲的下標(biāo)

此時(shí)分為兩種情況

  • 下標(biāo)位置上沒有元素,直接把元素方進(jìn)入
  • 該所以已有元素,判斷該位置的元素和當(dāng)前元素是否相等,使用equals來比較(默認(rèn)是比較兩個(gè)對象的地址)。如果兩只相等則直接覆蓋,如果不等則(Hash碰撞)在原元素下面使用鏈表的結(jié)構(gòu)存儲該元素(如果已存在鏈表,則插在鏈表尾部),每個(gè)元素節(jié)點(diǎn)都有一個(gè)next屬性指向下一個(gè)節(jié)點(diǎn),這就由數(shù)組結(jié)構(gòu)變成了數(shù)組+鏈表;因?yàn)殒湵碇性靥嗟臅r(shí)候回影響查找效率,所以當(dāng)鏈表的元素個(gè)數(shù)達(dá)到 8 的時(shí)候使用鏈表存儲就轉(zhuǎn)變成了使用紅黑樹存儲(當(dāng)紅黑樹上的節(jié)點(diǎn)數(shù)量小于 6 個(gè),會重新把紅黑樹變成單向鏈表數(shù)據(jù)結(jié)構(gòu)),原因就是紅黑樹是平衡二叉樹,在查找性能方面比聊表要高

HashMap取值的實(shí)現(xiàn)

  • 先調(diào)用k的hashCode()方法得出哈希值,并通過hash算法轉(zhuǎn)換成數(shù)組的下標(biāo)
  • 通過hash值轉(zhuǎn)換成數(shù)組下標(biāo)后,通過數(shù)組定位到下標(biāo)位置,如果改位置上什么都沒有,范圍null;如果該位置上有單向鏈表,那么就拿參數(shù)K和單向鏈表上的每一個(gè)節(jié)點(diǎn)的K進(jìn)行equals比較,如果所有equals都返回false,則返回null,如果有一個(gè)節(jié)點(diǎn)的K和參數(shù)K通過equals返回true,那么此時(shí)該節(jié)點(diǎn)的value就是要獲取的value值

擴(kuò)容

  • HashMap中有兩個(gè)重要參數(shù),初始容量大小和負(fù)載因子,在HashMap剛開始初始化的時(shí)候,使用默認(rèn)的構(gòu)造方法,會返回一個(gè)空的table,并且 thershold(擴(kuò)容閾值)為 0 ,因此第一次擴(kuò)容的時(shí)候默認(rèn)值就會是 16 ,負(fù)載因子默認(rèn)為 0.75 ,用數(shù)組容量乘以負(fù)載因子得到一個(gè)值,一旦數(shù)組中存儲的元素個(gè)數(shù)超過這個(gè)值就會調(diào)用rehash方法將數(shù)組容量增加到原來的兩倍,threshold也會變?yōu)樵瓉淼膬杀?/li>
  • 在做擴(kuò)容的時(shí)候會生成一個(gè)新的數(shù)組,原來的所有數(shù)據(jù)需要重新計(jì)算哈希碼值重新分配到新的數(shù)組,所以擴(kuò)容的操作非常消耗性能。所以,如果知道要存入的數(shù)據(jù)量比較大的話,可以在創(chuàng)建的時(shí)候先指定一個(gè)比較大的數(shù)據(jù)容量
  • 也可以引申到一個(gè)問題HashMap是先插入還是先擴(kuò)容:HashMap初始化后首次插入數(shù)據(jù)時(shí),先發(fā)生resize擴(kuò)容再插入數(shù)據(jù),之后每當(dāng)插入的數(shù)據(jù)個(gè)數(shù)達(dá)到threshold時(shí)就會發(fā)生resize,此時(shí)是先插入數(shù)據(jù)再resize

HashMap中的擴(kuò)容是在元素插入之前進(jìn)行的擴(kuò)容還是元素插入之后進(jìn)行的擴(kuò)容

在 JDK1.7中是在元素插入 前 進(jìn)行的擴(kuò)容,在JDK1.8 中是先加入元素 后 再判斷是否進(jìn)行擴(kuò)容

存儲元素超過閾值一定會進(jìn)行擴(kuò)容嗎

在 JDK1.7 中不一定,只有存儲元素超過閾值并且當(dāng)前存儲位置不為null,才會進(jìn)行擴(kuò)容,在 JDK1.8 中會進(jìn)行擴(kuò)容

HashMap和HashTable區(qū)別

線程方面

  • HashMap是非線程安全的,HashTable是線程安全的。 Hashtable的實(shí)現(xiàn)方法里面都添加了synchronized關(guān)鍵字來確保線程同步,因此相對而言HashMap性能會高一些,我們平時(shí)使用時(shí)若無特殊需求建議使用HashMap,在多線程環(huán)境下若使用HashMap需要使用Collections.synchronizedMap()方法來獲取一個(gè)線程安全的集合
  • HashMap的key可以為null,HashTable的key不可為null
  • HashMap是對Map接口的實(shí)現(xiàn),HashTable實(shí)現(xiàn)了Map接口和Dictionary抽象類
  • HashMap的初始容量為 16 ,Hashtable初始容量為 11 ,兩者的填充因子默認(rèn)都是 0.75 ,HashMap擴(kuò)容時(shí)是當(dāng)前容量翻倍即:capacity * 2,- Hashtable擴(kuò)容時(shí)是容量翻倍+1即:capacity * 2+1

HashMap中的hashcode怎么生成

調(diào)用對象key的hashCode方法,再對這個(gè)hashcode方法進(jìn)行一些右移以及異或運(yùn)算(使的hashCode的高位和低位都參與到運(yùn)算中);通過右移和異或運(yùn)算可以使hashMap的散列化更強(qiáng),提高h(yuǎn)ashMap的get方法的效率

為什么使用HashCode

HashCode的存在主要是為了查找的快捷性, HashCode是用來在散列存儲結(jié)構(gòu)中確定對象的存儲地址的 ( 用hashcode來代表對象在hash表中的位置 ) , hashCode存在的重要的原因之一就是在HashMap(HashSet其實(shí)就是HashMap)中使用(其實(shí)Object類的hashCode方法注釋已經(jīng)說明了),HashMap之所以速度 快 ,因?yàn)樗褂玫氖?散列表 ,根據(jù)key的hashcode值生成數(shù)組下標(biāo)(通過內(nèi)存地址直接查找,不需要判斷,但是需要多出很多內(nèi)存,相當(dāng)于以空間換時(shí)間)

equals方法和hashcode的關(guān)系

歸納總結(jié):

  • 若重寫了equals(Object obj)方法,則有必要重寫hashCode()方法
  • 若兩個(gè)對象equals(Object obj)返回true,則hashCode()有必要也返回相同的int數(shù)
  • 若兩個(gè)對象equals(Object obj)返回false,則hashCode()不一定返回不同的int數(shù)
  • 若兩個(gè)對象hashCode()返回相同int數(shù),則equals(Object obj)不一定返回true
  • 若兩個(gè)對象hashCode()返回不同int數(shù),則equals(Object obj)一定返回false
  • 同一對象在執(zhí)行期間若已經(jīng)存儲在集合中,則不能修改影響hashCode值的相關(guān)信息,否則會導(dǎo)致內(nèi)存泄露問題

key為null怎么辦

key為null的時(shí)候,只會放在hashMap的0位置(即key的hashCode為0,對數(shù)組長度取余后的下標(biāo)也是0),不會有鏈表 在HashMap源碼中對put方法對null做了處理,key為null的判斷后進(jìn)入putForNullKey(V value)這個(gè)方法,李里面for循環(huán)是在talbe[0]鏈表 中查找key為null的元素,如果找到,則將value重新賦值給這個(gè)元素的value,并返回原來的value。如果沒找到則將這個(gè)元素添加到talbe[0]鏈表的表頭

  1. /** 
  2.  * HashMap的put方法 
  3.  */ 
  4. public V put(K key, V value) { 
  5.     if (table == EMPTY_TABLE) { 
  6.         inflateTable(threshold); 
  7.     } 
  8.  
  9.     // keynull調(diào)用putForNullKey(value) 
  10.     if (key == nullreturn putForNullKey(value); 
  11.  
  12.     int hash = hash(key); 
  13.     int i = indexFor(hash, table.length); 
  14.     for (Entry<K,V> e = table[i]; e != null; e = e.next) { 
  15.         Object k; 
  16.         if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 
  17.             V oldValue = e.value; 
  18.             e.value = value; 
  19.             e.recordAccess(this); 
  20.             return oldValue; 
  21.         } 
  22.     } 
  23.     modCount++; 
  24.     addEntry(hash, key, value, i); 
  25.     return null
  26.  
  27. /** 
  28.  * Offloaded version of put for null keys 
  29.  */ 
  30. private V putForNullKey(V value) { 
  31.     // for循環(huán)處理key為空的情況 
  32.     for (Entry<K,V> e = table[0]; e != null; e = e.next) { 
  33.         if (e.key == null) { 
  34.             V oldValue = e.value; 
  35.             e.value = value; 
  36.             e.recordAccess(this); 
  37.             return oldValue; 
  38.         } 
  39.     } 
  40.     modCount++; 
  41.     addEntry(0, null, value, 0); 
  42.     return null

 【編輯推薦】

 

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2023-01-04 07:54:03

HashMap底層JDK

2023-10-18 10:55:55

HashMap

2023-07-11 08:00:00

2014-10-31 10:10:49

2021-07-23 13:34:50

MySQL存儲InnoDB

2021-08-29 07:41:48

數(shù)據(jù)HashMap底層

2025-05-08 08:45:00

內(nèi)存IO內(nèi)存CPU

2010-04-02 15:20:18

云存儲

2010-11-19 09:16:38

2018-09-29 15:27:05

BinderAPPAndroid

2023-01-13 16:53:17

Annotation底層元注解

2020-02-11 12:17:53

開發(fā)命令

2020-12-03 15:10:31

Linux開發(fā)

2021-04-14 14:46:13

前端Chrome插件

2019-12-16 10:01:54

Java開發(fā)Web

2015-01-06 14:39:41

云計(jì)算云存儲數(shù)據(jù)遷移

2016-06-20 10:59:53

SiriWWDC

2023-05-04 00:06:40

2016-09-12 14:33:20

javaHashMap

2021-01-21 05:52:11

斷言assert程序員
點(diǎn)贊
收藏

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