介紹
在Java中,您可能聽說過Map接口(它擴展了Collection接口)。有一些映射接口的實現類,其中一個這樣的類是HashMap(在java。跑龍套包)。表示為HashMap < K、V >K代表鍵,V代表值。簡單來說,HashMap < K、V >是一種數據結構,以鍵值對的形式存儲元素。這些鍵值對也稱為鍵值對條目HashMap。鍵是唯一的,不允許重複的鍵。它基於鍵存儲值,並且可以使用鍵訪問它。Hashmap允許多個空值和一個空鍵。
hashmap是非同步的,這意味著它們不是線程安全的。如果多個線程同時訪問hashmap,它們將在結構上修改該映射。hashmap是鍵值對的無序集合。它們不維護插入順序。與數組和鏈表相比,它們在檢索數據方麵要快得多,基本操作具有恒定的時間性能。hashmap的初始默認容量(可以存儲的元素數量)是16,默認負載因子是0.75。在後麵幾節中,我們將討論容量和負載因子。
層次結構
檢查上麵的層次圖;HashMap類擴展了AbstractMap類並實現了Map、Serializable和clone接口。
檢查上麵的層次圖;HashMap類擴展了AbstractMap類並實現了Map、Serializable和clone接口。
Hashmap類的聲明:
公共類HashMap
K:密鑰類型
V:值的類型
還要檢查Java初學者教程| Java概述.
hashmap中的構造函數
hashmap有四個構造函數,它們都有公共訪問說明符。
1.Hashmap ()
它是創建初始容量為的hashmap實例的默認構造函數
16,負載係數0.75。
HashMap
演示默認Hashmap構造函數的程序:
進口. io . *;進口java.util。*;public class Hashmap{public static void main(String args[]) {Hashmap hm = new Hashmap ();hm.put(“紅”,1);hm.put("藍色",2);hm.put(“綠色”,3);hm.put(“黃色”,4);System.out.println (hm);}}
輸出{紅色=1,藍色=2,黃色=4,綠色=3}[插入順序不保留]
2.HashMap (int initialCapacity)
此構造函數創建一個具有指定初始容量和的hashmap實例
默認負載係數0.75。
HashMap
演示Hashmap構造函數的程序:
進口. io . *;進口java.util。*;public class Hashmap{public static void main(String args[]) {Hashmap hm = new Hashmap (5);hm.put(“紅”,1);hm.put("藍色",2);hm.put(“綠色”,3);hm.put(“黃色”,4);System.out.println (hm);}}
輸出:{紅色=1,藍色=2,黃色=4,綠色=3}
3.HashMap(int initialCapacity, float loadFactor)
方法創建具有指定初始容量的hashmap實例
指定的負載因數。
HashMap
演示Hashmap構造函數的程序:
進口. io . *;進口java.util。*;public class Hashmap {public static void main(String args[]) {Hashmap hm = new Hashmap (5,0.75f);hm.put(“紅”,1);hm.put("藍色",2);hm.put(“綠色”,3);hm.put(“黃色”,4);System.out.println (hm);}}
輸出:
{紅色=1,藍色=2,黃色=4,綠色=3}
4.HashMap(地圖地圖)
這個構造函數創建一個hashmap實例,其映射與給定Map類似。
HashMap
演示Hashmap構造函數的程序:
進口. io . *;進口java.util。*;public class Hashmap {public static void main(String args[]) {Map hm = new Hashmap ();hm.put(“紅”,1);hm.put("藍色",2);hm.put(“綠色”,3);hm.put(“黃色”,4);System.out.println (hm);HashMap hm1 = new HashMap(hm);System.out.println (hm1); } }
輸出:
{紅色=1,藍色=2,黃色=4,綠色=3}
{紅色=1,藍色=2,黃色=4,綠色=3}
hashmap的操作
hashmap包括基本操作,如添加、獲取、更新和刪除元素,就像任何其他數據結構一樣。基本操作如下:
1.添加元素
要在Hashmap中插入元素或條目,可以使用把(K、V)方法使用。
K:密鑰類型
V:值的類型
演示put方法的程序:
進口. io . *;進口java.util。*;public class Hashmap {public static void main(String args[]) {Map hm = new Hashmap ();hm.put(“紅”,1);hm.put("藍色",2);hm.put(“綠色”,3);hm.put(“黃色”,4);System.out.println (hm);}}
輸出:
{紅色=1,藍色=2,黃色=4,綠色=3}
2.刪除元素
的刪除(K)方法將鍵作為參數,並刪除映射上存在的給定鍵的條目。我們還有一個刪除(K、V)方法刪除條目。
使用remove()演示刪除操作的程序:
進口. io . *;進口java.util。*;public class Hashmap {public static void main(String args[]) {Map hm = new Hashmap ();hm.put(“紅”,1);hm.put("藍色",2);hm.put(“綠色”,3);hm.put(“黃色”,4);System.out.println (hm);hm.remove(藍色);//刪除藍鍵System.out.println(hm); } }
輸出:
{紅色=1,藍色=2,黃色=4,綠色=3}
{紅色=1,黃色=4,綠色=3}
刪除(K、V):這個方法接受key和value作為參數,隻有當key和value都匹配時才刪除條目。
使用remove(K, V)刪除條目的程序:
進口. io . *;進口java.util。*;public class Hashmap {public static void main(String args[]) {Map hm = new Hashmap ();hm.put(“紅”,1);hm.put("藍色",2);hm.put(“綠色”,3);hm.put(“黃色”,4);System.out.println (hm);hm.remove(“藍色”,3);System.out.println (hm);; hm.remove("Blue",2); System.out.println(hm); } }
輸出:
{紅色=1,藍色=2,黃色=4,綠色=3}
{紅色=1,藍色=2,黃色=4,綠色=3}
{紅色=1,黃色=4,綠色=3}
3.訪問元素和遍曆hashmap
3.1使用get(K)訪問與某個鍵關聯的一個特定值
hashmap中的值可以使用該方法訪問得到(K).該鍵必須在參數中傳遞,存儲在該鍵中的值將被獲取。
編寫使用get(K)方法訪問值的程序:
進口. io . *;進口java.util。*;public class Hashmap{public static void main(String args[]) {Hashmap hm = new Hashmap ();hm.put(“紅”,1);hm.put("藍色",2);hm.put(“綠色”,3);hm.put(“黃色”,4);System.out.println (hm);System.out.println (hm.get(“綠色”);}}
輸出:
{紅色=1,藍色=2,黃色=4,綠色=3}
3.
3.2隻能訪問元素的鍵
如果您隻想檢索鍵集,鍵盤()方法將隻返回hashmap中的鍵集。
顯示keySet()方法用法的程序:
進口. io . *;進口java.util。*;public class Hashmap{public static void main(String args[]) {Hashmap hm = new Hashmap ();hm.put(“紅”,1);hm.put("藍色",2);hm.put(“綠色”,3);hm.put(“黃色”,4);System.out.println (hm);System.out.println (hm.keySet ());}}
輸出:
{紅色=1,藍色=2,黃色=4,綠色=3}
[紅,藍,黃,綠]
3.3隻訪問元素的值
的值()方法幫助獲取值集.
顯示values()用法的程序:
進口. io . *;進口java.util。*;public class Hashmap{public static void main(String args[]) {Hashmap hm = new Hashmap ();hm.put(“紅”,1);hm.put("藍色",2);hm.put(“綠色”,3);hm.put(“黃色”,4);System.out.println (hm);System.out.println (hm.values ());}}
輸出:
{紅色=1,藍色=2,黃色=4,綠色=3}
[1,2,4,3]
3.4訪問HashMap表項
的entrySet ()方法將返回條目集(
顯示entrySet()用法的程序:
進口. io . *;進口java.util。*;public class Hashmap{public static void main(String args[]) {Hashmap hm = new Hashmap ();hm.put(“紅”,1);hm.put("藍色",2);hm.put(“綠色”,3);hm.put(“黃色”,4);System.out.println (hm);System.out.println (hm.entrySet ());}}
輸出:
{紅色=1,藍色=2,黃色=4,綠色=3}
[紅色=1,藍色=2,黃色=4,綠色=3]
3.5遍曆HashMap
在了解了如何訪問hashmap中的元素之後,讓我們看看如何迭代或遍曆hashmap.其思想是使用for-each循環遍曆一組條目,然後使用for-each循環訪問條目中的鍵和值getKey ()而且getValue ()方法。我們使用地圖。條目(K, V) that allows us to access the entries of a map.
編寫遍曆hashmap條目的程序:
進口. io . *;進口java.util。*;public class Hashmap{public static void main(String args[]) {Hashmap hm = new Hashmap ();hm.put(“紅”,1);hm.put("藍色",2);hm.put(“綠色”,3);hm.put(“黃色”,4);System.out.println (hm);(地圖。條目 e: hm.entrySet()) { System.out.println(e.getKey()+","+e.getValue()); } } }
輸出:
{紅色=1,藍色=2,黃色=4,綠色=3}
紅色,1
藍色,2
黃色,4
綠色,3
4.更新值
如果要更新存儲在給定鍵中的值,可以使用把(K、V)或
替換()方法。
使用put()更新值的程序:
進口. io . *;進口java.util。*;public class Hashmap{public static void main(String args[]) {Hashmap hm = new Hashmap ();hm.put(“紅”,1);hm.put("藍色",2);hm.put(“綠色”,3);hm.put(“黃色”,4);System.out.println (hm);hm.put(“黃色”,5);//更新鍵值Yellow System.out.println(hm); } }
輸出:
{紅色=1,藍色=2,黃色=4,綠色=3}
{紅色=1,藍色=2,黃色=5,綠色=3}
使用replace(K,V)更新程序:
進口. io . *;進口java.util。*;public class Hashmap{public static void main(String args[]) {Hashmap hm = new Hashmap ();hm.put(“紅”,1);hm.put("藍色",2);hm.put(“綠色”,3);hm.put(“黃色”,4);System.out.println (hm);hm.replace(“黃色”,6);System.out.println (hm); } }
輸出:
{紅色=1,藍色=2,黃色=4,綠色=3}
{紅色=1,藍色=2,黃色=6,綠色=3}
hashmap的特性
Hashmap是一個基於map的集合類,它包含基於鍵的值。讓我們來討論一下它的一些關鍵特性:
- 它是一個無序的集合;也就是說,它不會按照插入鍵和值的順序維護鍵和值。
- 它不能有重複的鍵;但是,它可以有重複的值。
- 它允許一個空鍵和多個空值。
- HashMap使用內部類進入< K、V >在多個單鏈表的節點中存儲數據。
- 其初始默認容量為16,負載係數為0.75
- 它們不是同步的(不是線程安全的),因為多個線程在訪問時可以修改它們的結構。因此,我們必須從外部同步這些並發的修改。我們可以用collections . synchronizedmap (Hashmap)讓它同步。
- 它使用了一種叫做哈希將鍵轉換為更短的哈希鍵,從而更容易從哈希映射中插入和檢索數據。我們將在接下來的章節中詳細了解Hashmap的工作原理。
hashmap的內部結構
考慮到hashmap的內部結構,它有一個節點< K、V >哪個代表內部類進入< K、V >用於存儲hashmap的映射。每個鍵值對存儲在Entry
- 散列鍵(散列後獲得的較短的鍵)
- 關鍵
- 價值
- 節點next(對另一個條目的引用,就像單鏈表一樣)
了解HashMap中節點的要點:
- hash屬性存儲鍵的hashcode。
- Key屬性存儲鍵,它是final類型。
- 屬性保存元素的值。
- 條目
next保存指向下一個鍵值對的指針。
內部類Entry的聲明
靜態類Entry實現Map。條目{int哈希;最後的K鍵;V值;條目< K、V >下;}
HashMap中桶的概念
桶是存儲元素的節點或項的數組。許多節點可以擁有類似的存儲桶。hashmap像單鏈表一樣存儲元素,條目列表被稱為桶。這些節點通過鏈表連接起來。hashmap的容量和桶的個數有如下關係:
HashMap容量=桶數*負載因子
hashmap的結構
HashMap的內部工作
Hashmap使用一種叫做散列。方法將給定鍵轉換為哈希鍵的過程hashCode ()方法。哈希還涉及equals ()方法檢查鍵是否相等。哈希用於更快地索引和檢索項目。hashmap的性能基於hashcode()方法,因此應該仔細選擇該方法。下麵讓我們討論hashCode和equals方法。
1.hashCode ():該方法生成對象的hashcode,並以整數形式返回傳遞的對象的內存引用。它返回每個實例唯一的隨機整數。這種方法的結果稱為a哈希.
語法: public int hashCode()
2.equals ():Hashmap使用這個方法來檢查兩個對象是否相等。如果該方法返回true,則它們相等,否則不相等。
語法:boolean =(對象ob)
顯示equals()用法的程序:
進口. io . *;進口java.util。*;public class Hashmap{public static void main(String args[]) {Hashmap hm = new Hashmap ();HashMap hm1 = new HashMap();hm.put(“紅”,1);hm.put("藍色",2);hm.put(“綠色”,3);hm.put(“黃色”,4);System.out.println (hm);hm1.put(“紅”,1); hm1.put("Blue",2); hm1.put("Green",3); hm1.put("Yellow",4); System.out.println(hm1); System.out.println(hm.equals(hm1)); } }
輸出:
{紅色=1,藍色=2,黃色=4,綠色=3}
{紅色=1,藍色=2,黃色=4,綠色=3}
真正的
碰撞
當不同的鍵產生相同的hashcode值,並且元素已經存在於該索引值時,就會發生衝突。為了避免或減少衝突,應該使用一個好的哈希函數,以確保值在整個哈希映射中的最佳分布。當發生衝突時,我們使用鏈接技術,如上麵的第二個例子所示,來分布值。
哈希計算索引
索引是在哈希中生成的,以減少數組的大小。如果將鍵的hashcode用作索引,則獲得的整數值可能很大,可能會增加數組的大小。
該指數的計算公式如下:
索引= hashCode(Key) & (n-1)
N =數組/桶的大小
(默認n = 16)
Put()操作的散列
讓我們考慮一個默認容量為16 (n=16)的空hashmap。
1.沒有碰撞:假設你想把新建地圖中的條目(" welcome ",15)。
- 根據哈希的概念,哈希將首先使用hashCode(鍵)生成。
- 計算hash = hashCode(" welcome ");[假設是200]
- 計算索引= hash &(16-1),[計算結果為8]
- 創建一個帶有散列、鍵、值和引用指針的節點/條目對象。
- 如果該對象為空,則將其放在索引值8處。
2.碰撞:有時,可能會出現索引相同的情況,並且可能發生碰撞。現在讓我們嚐試在hashmap中插入(" wait ",16)。
- 計算hash = hashCode(" wait ");[假設是120]
- 計算索引= hash &(16-1),[計算結果為8]
- 創建一個帶有散列、鍵、值和引用指針的節點對象。
- 如果沒有其他值,將該對象放置在索引值8處。
- 如果有一些值放在那裏,就像在我們的例子中,它是一個碰撞狀態。
- 萬一發生碰撞,請檢查equals ()如果鍵相似。
- 如果equals()方法返回true,則將該值替換為當前值。
- 如果equals()方法返回false,則將這個新節點對象通過具有相同索引值的鏈表指向前一個節點。(鏈接方法)
- 在本例中,由於鍵、歡迎鍵和等待鍵是不同的,我們將使用鏈接列表放置一個新節點。
Get()操作的散列
讓我們看看如何使用哈希來實現get操作。get(Key)用於獲取給定鍵的值。
例子:沒有碰撞
假設您想要找到鍵“welcome”的值,請遵循以下哈希步驟。
- 計算hash = hashCode(" welcome ");(假設200年)
- 計算索引=哈希& (n-1), n=16[索引計算結果為8]
- 檢查索引8;如果此鍵與使用equals()方法的元素的鍵匹配,則返回該值。
- 如果鍵不匹配,則檢查下一個元素的鍵,依此類推。
- 在本例中,鍵匹配,因此將返回鍵“welcome”的值,即15。
例子:碰撞
假設你想要找到鍵“wait”的值:
- 計算hash = hashCode(" wait ");(假設120年)
- 計算索引=哈希& (n-1), n=16[索引計算結果為8]
- 檢查索引;如果此鍵與使用equals()方法的元素的鍵匹配,則返回該值。
- 在這裏,它不匹配,所以檢查列表中的下一個元素(下一個節點)。該索引的下一個鍵正在等待。重新檢查鑰匙;它們現在匹配了,所以鍵“wait”[即16]的值將被返回。
- 如果該節點的下一個引用為空,則返回空,否則移動到下一個節點並重複鍵匹配過程。
hashmap的性能
hashmap的性能基於兩個重要因素:
- 初始容量
- 負荷係數
初始容量:創建hashmap實例時的初始桶數。默認值為16。也就是說,最初哈希映射可以存儲16個鍵值元素。
負荷係數:它衡量的是在hashmap容量增加之前允許填充多少百分比。默認負載因子值為0.75,通常在0到1之間。
與性能相關的其他術語有:
閾值:它是負載因子和hashmap容量的乘積。默認閾值為0.75*16= 12。當hashmap中填充了12個元素時,我們需要停止向其中插入更多的元素。將進行重哈希,這將使hashmap的容量增加一倍。
再處理:這是一種在達到閾值時將容量翻倍的方法。當超過閾值時,就會重新散列,這樣桶的容量現在是原來的兩倍,操作所需的時間也更短。
HashMap的時間複雜度
說到時間複雜度HashMap的性能操作取決於哈希函數實現.如果哈希代碼實現良好(沒有哈希衝突),則最佳、最差和平均時間複雜度為O (1).在哈希碼實現不好的情況下(哈希會產生衝突),複雜性就會增加O (n).此外,對hashmap的迭代取決於它的容量和鍵-值對。如果容量較大,迭代次數會增加,這會增加時間複雜度,影響性能。
性能改進
關於Hashmap中的性能改進,必須適當選擇兩個因素優化哈希函數而且能力.哈希函數的實現應該是這樣的,即哈希代碼對更少的衝突給予no。保持高容量將增加迭代和時間複雜性,因此必須仔細選擇這兩個因素。
在JAVA 8中所做的更改:
JAVA 8中做了一些哈希映射性能改進,以處理哈希衝突。在Java 8之前,在哈希衝突的情況下,哈希映射的性能很低,這對複雜性有影響。由於衝突,鍵和值都被放在一個節點中,在最壞的情況下,由於鏈表遍曆,複雜度為O(n)。變更如下:
- 最初,散列映射將把條目存儲在一個鏈表中,但當達到閾值時,將使用自平衡BST樹而不是鏈表。使用BST的好處是我們得到的最壞情況的複雜度是O(log n)。
hashmap中的方法
put(K鍵,V值) | 在映射中插入一個條目。 |
putAll(地圖地圖) | 在映射中插入指定的映射。 |
putIfAbsent(K鍵,V值) | 僅在鍵不存在時插入條目。 |
刪除(K鍵) | 刪除指定鍵的條目。 |
刪除(K鍵,V值) | 刪除指定鍵和值的條目。 |
clear () | 從映射中移除所有映射。 |
isEmpty () | 如果映射沒有鍵值映射,則返回true。 |
尺寸() | 返回鍵值映射的個數。 |
鍵盤() | 在hashmap中返回一組鍵。 |
值() | 在hashmap中返回一組值。 |
entrySet () | 在hashmap中返回一組條目(K, V)。 |
得到(K鍵) | 返回與給定鍵相關聯的值。 |
替換(K鍵,V值) | 將指定的鍵替換為指定的值。 |
替換(K鍵,V舊值,V新值) | 將指定鍵的舊值替換為新值。 |
containsKey (K鍵) | 如果指定的鍵存在於hashmap中,則返回true。 |
containsValue (V值) | 如果指定的值存在於hashmap中,則返回true。 |
hashCode () | 以整數形式返回對象的內存地址 |
=(對象O) | 將指定對象與映射進行比較,如果相同則返回true。 |
克隆() | 返回hashmap實例的淺拷貝。 |
getOrDefault(K鍵,V默認值) | 返回給定鍵映射到的值,如果鍵未映射則返回默認值。 |
空白forEach (BiConsumer < ?超級K, ?超級V>動作) | 它將對所有條目執行給定的操作,直到它們全部被處理或拋出異常。 |
V merge(K鍵,V值,biffunction 的remappingFunction | 如果指定的鍵未映射到任何值,或者鍵為空,則將其映射為給定值。 |
空白replaceAll (BiFunction < ?超級K, ?超級V, ?擴展V>函數) | 它將在處理後用函數的結果替換每個條目值。 |
V計算(K鍵,biffunction 的remappingFunction | 計算指定鍵及其當前映射值的映射。如果當前沒有映射,則返回null。 |
V computeIfAbsent(K鍵,函數的映射函數 | 如果指定的鍵還沒有與某個值相關聯(或映射為null),則使用給定的映射函數計算值,並將其輸入到此映射中,除非為null。 |
V computeIfPresent(K鍵,biffunction 的remappingFunction | 給定鍵及其當前映射值(如果指定鍵的值存在且非空),計算一個新的映射。 |
上麵定義的hashmap的其他基本函數的一些例子:
程序顯示hashmap的大小:
進口. io . *;進口java.util。*;public class Hashmap{public static void main(String args[]) {Hashmap hm = new Hashmap ();hm.put(“紅”,1);hm.put("藍色",2);hm.put(“綠色”,3);hm.put(“黃色”,4);System.out.println (hm);System.out.println (hm.size ());}}
輸出:
{紅色=1,藍色=2,黃色=4,綠色=3}
4
編程顯示putAll()和putIfAbsent()方法:
進口. io . *;進口java.util。*;public class Hashmap{public static void main(String args[]) {Hashmap hm = new Hashmap ();hm.put(“紅”,1);hm.put("藍色",2);hm.put(“綠色”,3);hm.put(“黃色”,4);System.out.println (hm);HashMap hm1 = new HashMap();hm1.putAll (hm); //putAll System.out.println(hm1); hm.putIfAbsent("Orange",7); //putIfAbsent System.out.println(hm); } }
輸出:
{紅色=1,藍色=2,黃色=4,綠色=3}
{紅色=1,藍色=2,黃色=4,綠色=3}
{紅色=1,藍色=2,黃色=4,橙色=7,綠色=3}
編程來顯示containsKey()和containsValue()方法:
進口. io . *;進口java.util。*;public class Hashmap{public static void main(String args[]) {Hashmap hm = new Hashmap ();hm.put(“紅”,1);hm.put("藍色",2);hm.put(“綠色”,3);hm.put(“黃色”,4);System.out.println (hm);System.out.println (hm.containsKey(“綠色”);System.out.println (hm.containsKey(“橙色”)); System.out.println(hm.containsValue(3)); System.out.println(hm.containsValue(7)); } }
輸出:
{紅色=1,藍色=2,黃色=4,綠色=3}
真正的
假
真正的
假
同步的HashMap
如上所述,hashmap是非同步的,這意味著它們不是線程安全的。當同時訪問hashmap時,多個線程可以從結構上改變它,然後必須從外部同步。外部同步可以通過以下方式完成:
映射m =集合。synchronizedMap (Hashmap地圖);
想知道去哪裏學習夢寐以求的課程在免費索取技能?看看關於beplay2018官网卓越學習學院.