欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中map內(nèi)部存儲(chǔ)方式解析

 更新時(shí)間:2017年10月01日 15:10:26   作者:清空萬(wàn)里111  
這篇文章主要介紹了Java中map內(nèi)部存儲(chǔ)方式解析的相關(guān)內(nèi)容,涉及其實(shí)現(xiàn)方式,以及對(duì)存儲(chǔ)方式作了簡(jiǎn)單的比較,具有一定參考價(jià)值,需要的朋友可了解下。

Map,即映射,也稱(chēng)為 鍵值對(duì),有一個(gè) Key, 一個(gè) Value 。

比如 Groovy 語(yǔ)言中,  def  map = ['name' : 'liudehua', 'age' : 50 ] ,則 map[ 'name' ]  的值是 'liudehua'。
那么 Map 內(nèi)部存儲(chǔ)是怎么實(shí)現(xiàn)的呢?   下面慢慢講解.

一、 使用 拉鏈?zhǔn)酱鎯?chǔ)

這個(gè)以 Java 中的 HashMap 為例進(jìn)行講解。   HashMap 的內(nèi)部有個(gè)數(shù)組 Entry[]  table, 這個(gè)數(shù)組就是存放數(shù)據(jù)的。

Entry 類(lèi)的定義大致是 :

class Entry {
Object key
Object value
Entry next;
}

所以, Entry[]  table  的每個(gè)元素都是一個(gè)鏈表,即 HashMap 的內(nèi)部存儲(chǔ)是 數(shù)組 + 鏈表,即拉鏈?zhǔn)酱鎯?chǔ)。

當(dāng)往 HaspMap 中 put(key,  value) 數(shù)據(jù)時(shí),先進(jìn)行  key.hashCode()  &  (table.length() - 1) ,得到一個(gè)小于 table.length() 的值, 稱(chēng)為 index, 則這個(gè)新的 Entry 就屬于 table[index] 這個(gè)鏈表了 ( 如果鏈表還不存在,則把這個(gè)新的 Entry 作為鏈表的頭部了 );  然后開(kāi)始從前往后遍歷  table[index] 這個(gè)鏈表,如果 key.equals( entry.key ), 那么表示這個(gè) key 已經(jīng)有了舊值,則替換 value 的值即可;

否則,把這個(gè)新的 Entry 插入到 table[index] 鏈表的最前面.

以上就是 HashMap 的存儲(chǔ)方式介紹了, 而且可以知道,作為 HashMap 的 Key, 它的 hashCode() 和 equals() 方法都被使用了

二、數(shù)組存儲(chǔ)

1.分散的數(shù)組存儲(chǔ)

這個(gè)以 ThreadLocal  和 ThreadLocal.Values  類(lèi)為例進(jìn)行講解。 Values 類(lèi)里面有兩個(gè)變量, Object[]  table, 和 mask , table 就是存儲(chǔ)數(shù)據(jù)的數(shù)組了,table 的長(zhǎng)度是 2 的倍數(shù) ,  mask 的值就是  table.length - 1 ;  這一點(diǎn)和 HashMap 的內(nèi)部存儲(chǔ)很像。  不過(guò) table 中的每個(gè)元素就不是鏈表了。

當(dāng)往  Values 中進(jìn)行 put(key, value) 時(shí),先進(jìn)行 key.hashCode & mask ,得到一個(gè)小于 table.length 的值,稱(chēng)為 index (與上面的 HashMap 好像,哈哈), 然后去檢查 table[index] 的值,如果不存在,則在 table[index] 處放入 key, table[index + 1] 處放入 value; 如果已經(jīng)存在了,且 key.equals( oldKey ) 不成立,即發(fā)生了沖突,那么 index = index + 2 ( 此處是 + 2,因?yàn)?key ,value 兩個(gè)是挨著放的,一個(gè)元素占倆坑 ) ; 往下一地方找找,如果再?zèng)_突,再找,直到找到一個(gè)可插入的地方,把 table[index] = key, table[index + 1] = value; 

有兩處需要注意:

key.hashCode() 必須是 2 的倍數(shù), 否則 index 的值有可能為奇數(shù),如此就可能發(fā)生沖突了.  可參考 ThreadLocal.hash 這個(gè)成員變量

table 內(nèi)部的數(shù)據(jù)是分散著存儲(chǔ)的.

2.連續(xù)的數(shù)組存儲(chǔ)

這個(gè)以 Android 中新增的 ArrayMap 為例進(jìn)行分析( 據(jù)說(shuō)沒(méi) ArrayMap 是用來(lái)替換 HashMap 的哈 ),  ArrayMap 中有兩個(gè)主要變量, int[]  mHashes, Object[]  mArrays.

mHashes 主要是存放 key 的 hash 值的, mArrays 是用來(lái)存放數(shù)據(jù)的,它也是奇數(shù)存放 key ,偶數(shù)存放 value , key 和 value 順序排列( 這個(gè)和 TheadLocal.value 中的 table 存儲(chǔ)方式很像 )。  mArrays 的長(zhǎng)度是 mHashes 的 2 倍,畢竟 mArrays 是 key, value 都要存嘛~

mHashes 中存放 key 的 hash 值,是從小到大排列的,如果有多個(gè) key 的 hash 值有一樣的,那么就挨著排列

當(dāng)往 ArrayMap 中進(jìn)行 put(key, value) 時(shí),先 int hash = key.hashCode, 然后通過(guò)二分查找在 mHashes 中查找 hash 的位置( 如果里面有,就返回,如果無(wú),就先找到最接近的位置,然后進(jìn)行取反操作并返回 )  index,如果 index > 0 ,那么再去 mArrays 中 2 * index 處獲取 key 值,比對(duì)兩個(gè) key 是否 equals(), 如果不相等,那么再分別向上、向下查找附近相同 hash 值的 key ,看是否有 equals() 的 key, 若有,則替換,若無(wú),則插入;    如果 index < 0 ,表示之前沒(méi)有相等 hash 的 key 插入過(guò),那么 index = ~index( 再次取反,就是個(gè)正數(shù)了,代辦要插入的位置), 再在 mHashes 的 index 處插入 hash, 在 mArrays 的 2 * index 處插入 key, 在 (2 * index ) + 1 處,插入 value .

注意:

mHashes 和 mArrays 在插入新數(shù)據(jù)時(shí),都需要把插入位置后面的數(shù)據(jù)向后移動(dòng)一個(gè)單位,這個(gè)對(duì)于頻繁插入、刪除的動(dòng)作來(lái)說(shuō)消耗比較大.

key 的 hash 大小決定了插入的順序

3.以數(shù)字為 key 的數(shù)組存儲(chǔ)

這類(lèi)的 map 比較特殊,key 是數(shù)字類(lèi)型。  這個(gè)以 Android 中新增的 SparseArray 進(jìn)行分析。 SparseArray 中有兩個(gè)主要變量, int[]  mKeys  和  Object[]  mValues , mKeys 是存放 key 的,是個(gè)有序數(shù)組,從小到大排列;  mValues 是與 mKeys 一一對(duì)應(yīng)的 value 值集合.   mKeys 和 mValues 的長(zhǎng)度是相等的。

當(dāng)往  SparseArray 中 put(key, value) 時(shí),先用二分查找在 mKeys 中查找 key 所在的位置 (如果找到,返回; 如果沒(méi)有找到,則找到它應(yīng)該插入的位置,取反并返回) ,記為 index, index > 0 ,則直接在 mValues[index] 處替換 value; 如果 index < 0 ,則 index = ~index, 即取反, 然后在 mKeys 的 index 處插入 key , 在 mValues[index] 處插入 value ,之前的數(shù)據(jù)自 index 處后移一個(gè)單位。

注意:

mKeys 和 mArrays 的數(shù)據(jù)插入時(shí),都是要進(jìn)行數(shù)據(jù)移動(dòng)的,對(duì)頻繁插入、刪除的 map 來(lái)說(shuō)消耗很大.
最后了,對(duì)它們的優(yōu)缺點(diǎn)做些對(duì)比。

HashMap : 內(nèi)存占用較大,增、刪的效率較高,改、查的效率一般

ThreadLocal.Values :  內(nèi)存占用一般,當(dāng)數(shù)據(jù)量比較小時(shí),增刪改查的效率高;數(shù)據(jù)量大時(shí),增刪改查效率一般

ArrayMap: 內(nèi)存占用較小,改、查的效率高,增、刪的效率較低

SparseArray : 內(nèi)存占用較小,改、查的效率高,增、刪的效率低,且主鍵是數(shù)字

總結(jié)

我們不評(píng)判哪種存儲(chǔ)方式好,一切都要以實(shí)際情況實(shí)際分析,找出最符合的那種存儲(chǔ),哈哈~。希望對(duì)大家有所幫助。感興趣的朋友可以參閱:Javabean和map相互轉(zhuǎn)化方法代碼示例  淺談對(duì)象與Map相互轉(zhuǎn)化  Struts2 使用OGNL遍歷map方法詳解等。感謝大家對(duì)本站的支持。

相關(guān)文章

  • java實(shí)現(xiàn)簡(jiǎn)易點(diǎn)菜器

    java實(shí)現(xiàn)簡(jiǎn)易點(diǎn)菜器

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)易點(diǎn)菜器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • Java Jackson之ObjectMapper常用用法總結(jié)

    Java Jackson之ObjectMapper常用用法總結(jié)

    這篇文章主要給大家介紹了關(guān)于Java Jackson之ObjectMapper常用用法的相關(guān)資料,ObjectMapper是一個(gè)Java庫(kù),用于將JSON字符串轉(zhuǎn)換為Java對(duì)象或?qū)ava對(duì)象轉(zhuǎn)換為JSON字符串,需要的朋友可以參考下
    2024-01-01
  • zookeeper的Leader選舉機(jī)制源碼解析

    zookeeper的Leader選舉機(jī)制源碼解析

    這篇文章主要為大家介紹了zookeeper的Leader選舉源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • Spring框架花式創(chuàng)建Bean的n種方法(小結(jié))

    Spring框架花式創(chuàng)建Bean的n種方法(小結(jié))

    這篇文章主要介紹了Spring框架花式創(chuàng)建Bean的n種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • SpringBoot的自定義banner使用方法

    SpringBoot的自定義banner使用方法

    這篇文章主要介紹了SpringBoot的自定義banner使用方法,在Spring Boot中,你可以通過(guò)定制Banner來(lái)個(gè)性化你的應(yīng)用程序啟動(dòng)時(shí)的輸出,Banner是一個(gè)在應(yīng)用程序啟動(dòng)時(shí)顯示的ASCII藝術(shù)字形式的標(biāo)志,用于增加應(yīng)用程序的識(shí)別度和個(gè)性化,需要的朋友可以參考下
    2024-01-01
  • 一文搞懂Spring中@Autowired和@Resource的區(qū)別

    一文搞懂Spring中@Autowired和@Resource的區(qū)別

    @Autowired?和?@Resource?都是?Spring/Spring?Boot?項(xiàng)目中,用來(lái)進(jìn)行依賴(lài)注入的注解。它們都提供了將依賴(lài)對(duì)象注入到當(dāng)前對(duì)象的功能,但二者卻有眾多不同,并且這也是常見(jiàn)的面試題之一,所以我們今天就來(lái)盤(pán)它
    2022-08-08
  • SpringBoot中的手動(dòng)提交事務(wù)

    SpringBoot中的手動(dòng)提交事務(wù)

    在Spring框架中使用@Transactional注解通常管理事務(wù),但在多線(xiàn)程環(huán)境下此方法失效,本文討論了手動(dòng)事務(wù)的必要性及其實(shí)現(xiàn)方式,探討了Spring的七種事務(wù)傳播行為和數(shù)據(jù)庫(kù)的四大特性與隔離級(jí)別,了解這些可以幫助開(kāi)發(fā)者在無(wú)法使用聲明式事務(wù)時(shí)
    2024-09-09
  • java 數(shù)據(jù)結(jié)構(gòu)之棧與隊(duì)列

    java 數(shù)據(jù)結(jié)構(gòu)之棧與隊(duì)列

    這篇文章主要介紹了java 數(shù)據(jù)結(jié)構(gòu)之棧與隊(duì)列的相關(guān)資料,這里對(duì)java中的棧和隊(duì)列都做出實(shí)現(xiàn)實(shí)例來(lái)幫助大家理解學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu),需要的朋友可以參考下
    2017-07-07
  • Spring實(shí)現(xiàn)加法計(jì)算器和用戶(hù)登錄功能

    Spring實(shí)現(xiàn)加法計(jì)算器和用戶(hù)登錄功能

    在前后端分離的Web開(kāi)發(fā)模式中,接口(API)扮演著至關(guān)重要的角色,它是前后端交互的橋梁,創(chuàng)建加法計(jì)算器和用戶(hù)登錄功能時(shí),介紹了接口測(cè)試和問(wèn)題解決的一般流程,如使用Postman測(cè)試接口、查看日志、處理緩存問(wèn)題等,確保開(kāi)發(fā)過(guò)程中的高效協(xié)作和問(wèn)題快速定位
    2024-10-10
  • SpringSecurity中的EnableWebSecurity注解啟用Web安全詳解

    SpringSecurity中的EnableWebSecurity注解啟用Web安全詳解

    這篇文章主要介紹了SpringSecurity中的EnableWebSecurity注解啟用Web安全詳解,@EnableWebSecurity是Spring?Security用于啟用Web安全的注解,典型的用法是該注解用在某個(gè)Web安全配置類(lèi)上,實(shí)現(xiàn)了接口,需要的朋友可以參考下
    2023-12-12

最新評(píng)論