搜尋
首頁Javajava教程Java提高篇(三三)-----Map總結

        在前面LZ詳細介紹了HashMap、HashTable、TreeMap的實現方法,從資料結構、實現原理、源碼分析三個方面進行闡述,對這個三個類應該有了比較清晰的了解,下面LZ就Map做一個簡單的總結。

        推薦閱讀:

         

java增進篇(二五)—–HashTable

       

Java提高篇(二六)-----hashCode Map

一、Map概述

        先看Map的結構示意圖

「鍵值」對映射的抽象介面。此映射不包括重複的鍵,一個鍵對應一個值。

       

SortedMap:有序的鍵值對接口,繼承Map接口。

        NavigableMap:繼承SortedMap,具有了針對給定搜尋目標傳回給定的導覽方法的介面。

        AbstractMap:實現了Map中大部分的函數介面。它減少了「Map的實作類別」的重複編碼。

        Dictionary:任何可將鍵映射到對應值的類別的抽象父類。目前被Map介面取代。

        TreeMap:有序散列表,並實現SortedMap 介面,底層透過紅黑樹實現。

        HashMap:是基於「拉鍊法」所實現的散列表。底層採用「數組+鍊錶」實作。

        WeakHashMap:基於「拉鍊法」所實現的雜湊列表。

        HashTable:基於「拉鍊法」所實現的雜湊。

       

二、內部雜湊: 雜湊映射技術

        幾乎所有通用Map都使用雜湊映射技術。對於我們程式設計師來說我們必須要對其有所了解。

        哈希映射技術是一種非常簡單的元素映射到陣列的技術。由於雜湊映射採用的是數組結果,那麼必然存在一中用於確定任意鍵存取數組的索引機制,該機制能夠提供一個小於數組大小的整數,我們將該機制稱為雜湊函數。在Java中我們不必為尋找這樣的整數而大傷腦筋,因為每個物件都必定存在一個傳回整數值的hashCode方法,而我們需要做的就是將其轉換為整數,然後再將該值除以數組大小取餘即可。如下:

int hashValue = Maths.abs(obj.hashCode()) % size;

下面是HashMap、HashTable的:

----------HashMap------------
//计算hash值
static int hash(int h) {
    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
}
//计算key的索引位置
static int indexFor(int h, int length) {
        return h & (length-1);
}
-----HashTable--------------
int index = (hash & 0x7FFFFFFF) % tab.length;     //确认该key的索引位置

 位置的索引代表了該節點在數組中的該節點。下圖為雜湊映射的基本原理圖:


         在該圖中1-4步驟是找到此元素在陣列中位置,5-8步驟是將該元素插入陣列中。在插入的過程中會遇到一點小挫折。在眾多肯能存在多個元素他們的hash值是一樣的,這樣就會得到相同的索引位置,也就說多個元素會映射到相同的位置,這個過程我們稱之為「衝突」。解決衝突的辦法是在索引位置處插入連結列表,並簡單地將元素新增至此連結列表。當然也不是簡單的插入,在HashMap中的處理過程如下:取得索引位置的鍊錶,如果該鍊錶為null,則將該元素直接插入,否則透過比較是否存在與該key相同的key,若存在則覆蓋原來key的value並傳回舊值,否則將該元素保存在鏈頭(最先保存的元素放在鏈尾)。以下是HashMap的put方法,該方法詳細展示了計算索引位置,將元素插入到適當的位置的全部過程:

public V put(K key, V value) {
        //当key为null,调用putForNullKey方法,保存null与table第一个位置中,这是HashMap允许为null的原因
        if (key == null)
            return putForNullKey(value);
        //计算key的hash值
        int hash = hash(key.hashCode());                 
        //计算key hash 值在 table 数组中的位置
        int i = indexFor(hash, table.length);            
        //从i出开始迭代 e,判断是否存在相同的key
        for (Entry<K, V> e = table[i]; e != null; e = e.next) {
            Object k;
            //判断该条链上是否有hash值相同的(key相同)
            //若存在相同,则直接覆盖value,返回旧value
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;    //旧值 = 新值
                e.value = value;
                e.recordAccess(this);
                return oldValue;     //返回旧值
            }
        }
        //修改次数增加1
        modCount++;
        //将key、value添加至i位置处
        addEntry(hash, key, value, i);
        return null;
    }

         HashMap
      如果我們查看其它的Map,發現其原理都差不多!

三、Map最佳化

         首先被映射,假設哈希映射的內部數組的大小只有1,所有的元素都將只有1,所有的元素都構成一個較大的位(從而一個長的大小(從而較大的大小)(從而較大地1,所有的元素都只有1,所有的元素都構成一個較大(從而一個長的)鍊錶。由於我們更新、訪問都要對這條鍊錶進行線性搜索,這樣勢必會降低效率。我們假設,如果存在一個非常大數組,每個位置鍊錶處都只有一個元素,在進行訪問時計算其 index 值就會獲得該對象,這樣做雖然會提高我們搜索的效率,但是它浪費了控制項。誠然,雖然這兩種方式都是極端的,但是它給我們提供了一種優化思路:使用一個較大的數組讓元素能夠均勻分佈。

在Map有兩個會影響到其效率,一是容器的初始化大小、二是負載因子。

3.1、調整實現大小

         在哈希映射表中,以內部數組中的每個位置稱為「儲存桶」(bucket),而可用桶數的儲存空間(即可用桶的數組”大小)稱作容量(capacity),我們為了讓Map物件能夠有效地處理任意數的元素,將Map設計成可以調整自身的大小。我們知道當Map中的元素達到一定量的時候就會調整容器本身的大小,但是這個調整大小的過程其開銷是非常大的。調整大小需要將原來所有的元素插入到新數組中。我們知道index = hash(key) % length。這樣可能會導致原先衝突的鍵不在衝突,不衝突的鍵現在衝突的,重新計算、調整、插入的過程開銷是非常大的,效率也比較低。所以,如果我們開始知道Map的預期大小值,將Map調整的足夠大,則可以大幅減少甚至不需要重新調整大小,這很有可能會提高速度。

下面是HashMap調整容器大小的過程,透過下面的程式碼我們可以看到其擴容過程的複雜性:

🎜🎜
void resize(int newCapacity) {
            Entry[] oldTable = table;    //原始容器
            int oldCapacity = oldTable.length;    //原始容器大小
            if (oldCapacity == MAXIMUM_CAPACITY) {     //是否超过最大值:1073741824
                threshold = Integer.MAX_VALUE;
                return;
            }

            //新的数组:大小为 oldCapacity * 2
            Entry[] newTable = new Entry[newCapacity];    
            transfer(newTable, initHashSeedAsNeeded(newCapacity));
            table = newTable;
           /*
            * 重新计算阀值 =  newCapacity * loadFactor >  MAXIMUM_CAPACITY + 1 ? 
            *                         newCapacity * loadFactor :MAXIMUM_CAPACITY + 1
            */
            threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);   
        }
        
        //将元素插入到新数组中
        void transfer(Entry[] newTable, boolean rehash) {
            int newCapacity = newTable.length;
            for (Entry<K,V> e : table) {
                while(null != e) {
                    Entry<K,V> next = e.next;
                    if (rehash) {
                        e.hash = null == e.key ? 0 : hash(e.key);
                    }
                    int i = indexFor(e.hash, newCapacity);
                    e.next = newTable[i];
                    newTable[i] = e;
                    e = next;
                }
            }
        }

3.2、负载因子

         为了确认何时需要调整Map容器,Map使用了一个额外的参数并且粗略计算存储容器的密度。在Map调整大小之前,使用”负载因子”来指示Map将会承担的“负载量”,也就是它的负载程度,当容器中元素的数量达到了这个“负载量”,则Map将会进行扩容操作。负载因子、容量、Map大小之间的关系如下:负载因子 * 容量 > map大小  ----->调整Map大小。

         例如:如果负载因子大小为0.75(HashMap的默认值),默认容量为11,则 11 * 0.75 = 8.25 = 8,所以当我们容器中插入第八个元素的时候,Map就会调整大小。

        负载因子本身就是在控件和时间之间的折衷。当我使用较小的负载因子时,虽然降低了冲突的可能性,使得单个链表的长度减小了,加快了访问和更新的速度,但是它占用了更多的控件,使得数组中的大部分控件没有得到利用,元素分布比较稀疏,同时由于Map频繁的调整大小,可能会降低性能。但是如果负载因子过大,会使得元素分布比较紧凑,导致产生冲突的可能性加大,从而访问、更新速度较慢。所以我们一般推荐不更改负载因子的值,采用默认值0.75.

最后

        推荐阅读:

        java提高篇(二三)—–HashMap

        java提高篇(二五)—–HashTable

        Java提高篇(二六)-----hashCode

        Java提高篇(二七)—–TreeMap

 


以上就是Java提高篇(三三)-----Map总结的内容,更多相关内容请关注PHP中文网(www.php.cn)!


陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
Java平台獨立性:與不同的操作系統的兼容性Java平台獨立性:與不同的操作系統的兼容性May 13, 2025 am 12:11 AM

JavaachievesPlatFormIndependencethroughTheJavavIrtualMachine(JVM),允許Codetorunondifferentoperatingsystemsswithoutmodification.thejvmcompilesjavacodeintoplatform-interploplatform-interpectentbybyteentbytybyteentbybytecode,whatittheninternterninterpretsandectectececutesoneonthepecificos,atrafficteyos,Afferctinginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginging

什麼功能使Java仍然強大什麼功能使Java仍然強大May 13, 2025 am 12:05 AM

JavaispoperfulduetoitsplatFormitiondence,對象與偏見,RichstandardLibrary,PerformanceCapabilities和StrongsecurityFeatures.1)Platform-dimplighandependectionceallowsenceallowsenceallowsenceallowsencationSapplicationStornanyDevicesupportingJava.2)

頂級Java功能:開發人員的綜合指南頂級Java功能:開發人員的綜合指南May 13, 2025 am 12:04 AM

Java的頂級功能包括:1)面向對象編程,支持多態性,提升代碼的靈活性和可維護性;2)異常處理機制,通過try-catch-finally塊提高代碼的魯棒性;3)垃圾回收,簡化內存管理;4)泛型,增強類型安全性;5)ambda表達式和函數式編程,使代碼更簡潔和表達性強;6)豐富的標準庫,提供優化過的數據結構和算法。

Java真的平台獨立嗎? '寫一次,在任何地方運行”如何起作用Java真的平台獨立嗎? '寫一次,在任何地方運行”如何起作用May 13, 2025 am 12:03 AM

javaisnotirelyplatemententedduetojvmvariationsandnativecodinteinteration,butitlargelyupholdsitsitsworapromise.1)javacompilestobytecoderunbythejvm

揭示JVM:您了解Java執行的關鍵揭示JVM:您了解Java執行的關鍵May 13, 2025 am 12:02 AM

thejavavirtualmachine(JVM)IsanabtractComputingmachinecrucialforjavaexecutionasitrunsjavabytecode,使“ writeononce,runanywhere”能力

Java仍然是基於新功能的好語言嗎?Java仍然是基於新功能的好語言嗎?May 12, 2025 am 12:12 AM

Javaremainsagoodlanguageduetoitscontinuousevolutionandrobustecosystem.1)Lambdaexpressionsenhancecodereadabilityandenablefunctionalprogramming.2)Streamsallowforefficientdataprocessing,particularlywithlargedatasets.3)ThemodularsystemintroducedinJava9im

是什麼使Java很棒?關鍵特徵和好處是什麼使Java很棒?關鍵特徵和好處May 12, 2025 am 12:11 AM

Javaisgreatduetoitsplatformindependence,robustOOPsupport,extensivelibraries,andstrongcommunity.1)PlatformindependenceviaJVMallowscodetorunonvariousplatforms.2)OOPfeatureslikeencapsulation,inheritance,andpolymorphismenablemodularandscalablecode.3)Rich

前5個Java功能:示例和解釋前5個Java功能:示例和解釋May 12, 2025 am 12:09 AM

Java的五大特色是多態性、Lambda表達式、StreamsAPI、泛型和異常處理。 1.多態性讓不同類的對象可以作為共同基類的對象使用。 2.Lambda表達式使代碼更簡潔,特別適合處理集合和流。 3.StreamsAPI高效處理大數據集,支持聲明式操作。 4.泛型提供類型安全和重用性,編譯時捕獲類型錯誤。 5.異常處理幫助優雅處理錯誤,編寫可靠軟件。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。