什麼是 Java 地圖接口
Java Map 接口是 Java Collection 框架的一部分,但它不是 Collection 接口的子類型。因此,與列表或其他集合對象相比,它的行為方式不同。Map<Key, Value> 的每個元素代表一個鍵值對。Key 和 value 都是一些對象。特定映射中的所有鍵都是唯一的,而值不是,因此它們可以重複。您可能會將 Java 中的 Map 視為一種字典或在線商店目錄,您可以在其中使用其唯一索引找到任何項目。鍵是 Map 中值的唯一標識符。例如,在 Map<String, Item> 中,String 是在線商店中某個 Item 的 ID。
根據文件 Map 有下一個子接口:
綁定;
- 並發映射<K,V> ;
- ConcurrentNavigableMap<K,V> ;
- 邏輯消息上下文;
- 消息上下文;
- 導航地圖<K,V> ;
- SOAP消息上下文;
- 排序映射<K,V>。
並實現類:
- 抽像地圖
- 屬性
- 授權提供者
- ConcurrentHashMap
- ConcurrentSkipListMap
- 枚舉圖
- 哈希表
- 哈希表
- IdentityHashMap
- 鍊錶
- 打印機狀態原因
- 特性
- 供應商
- 渲染提示
- 簡單綁定
- 表格數據支持
- 樹圖
- UI默認值
- WeakHashMap
- Java AbstractMap是一個抽像類,它實現了大部分 Map 接口。
- Java HashMap是一種使用哈希表存儲鍵值對的數據結構。
- Java TreeMap是一種使用樹的數據結構,即用排序的鍵顯示。
- WeakHashMap使用帶有弱鍵的哈希表,顯示的值如果不再使用可以被垃圾收集器刪除。
- LinkedHashMap是一個具有添加元素順序的映射,允許按插入順序進行迭代。
- EnumMap擴展了AbstractMap類以用於枚舉鍵。
IdentityHashMap在比較文檔時使用引用等價性檢查,映射與鍵比較使用
==操作而不是
equals()方法
在這裡,我們對 Map 接口最流行的實現感興趣:HashMap、TreeMap 和 LinkedHashMap。順便說一句,地圖元素的順序取決於具體的實現。比如說,TreeMap 和 LinkedHashMap 具有可預測的元素順序,而 HashMap 則沒有。
映射方法
任何 Map 的主要操作是元素的插入、刪除和查找。
- public Object put(Object key, Object value)將一個元素插入到地圖中。
- public void putAll(Map map)在地圖內部插入指定的地圖。
- public Object remove(Object key)根據指定的鍵刪除條目。
- public Object get(Object key)返回指定鍵的值。
- public boolean containsKey(Object key)從此映射中搜索指定的鍵
- public Set keySet()返回一個包含所有鍵的集合視圖
- public Set entrySet()返回一個包含所有鍵和值的 Set 視圖。
什麼是哈希表
什麼是哈希表?它是 Map<Key,Value> 接口最流行的實現。該數據結構基於散列原理。
HashMap工作的主要原理:散列
要了解什麼是哈希圖及其工作原理,讓我們先談談哈希和哈希函數。哈希函數只是數學意義上的函數。所以有一些輸入值(一個對象,一段數據)並且函數使用適當的規則將其轉換為輸出值 - 哈希。哈希通常是適當長度的十六進制數。轉換過程的規則可能不同,但都遵循以下原則:
- 特定的輸入(對象)具有特定的哈希碼。
- 如果兩個對象相等,則它們的哈希碼也相等。反之則不然。
- 如果哈希碼不同,則對象肯定不相等。
- 有時不同的對象可以有相同的散列碼。這是一個不太可能發生的事件,稱為“碰撞”,高質量的哈希函數應該將碰撞的可能性降到最低。
在 Java 中,每個對像都有一個哈希碼。它是通過 Object 類的 hashCode 方法計算的,它是所有 Java 對象的父類。通常,開發人員會為他們自己的類重寫此方法以及與之關聯的
equals方法。
HashMap:它是如何工作的
所以 Class HashMap<K,V> 因為每個 Map 實現都由鍵和值組成。它使用散列原則存儲密鑰。HashMap內部鍵值對存儲在“桶”中,這些桶共同構成一個“表”,內部是一個鍊錶數組,
初始大小為16. Java 中的 HashMap 使用鍵的哈希碼來確定鍵/值對應該映射到的桶: HashMap 棘手的特點是表 [] 的每個單元格(桶)不僅保留一對,而且保留幾對。它們不存儲為顯式對象(如 LinkedList),而是存儲為隱式鏈。由於每一對存儲到下一對的鏈接,因此創建了鏈。也就是說,所有的 HashMap 對都分散在 16 個鏈上。當您將新對放入表中時,會考慮密鑰的哈希值。此哈希不是鍵對像中內置的哈希碼函數。它被認為在0-15的範圍內。該對被添加到存儲在具有哈希索引的桶中的對鏈中。這種方法為我們提供了搜索加速。在通過鍵搜索一對時,無需遍歷整個表。考慮密鑰的散列,並且僅檢查存儲在具有散列索引的單元格中的鏈。如果 HashMap 中的對太多,鏈就會變得太長。然後數組的大小增加,重新計算所有存儲對象的哈希值,並將它們分散在新的鏈上。
哈希圖聲明
如果您轉到類 HashMap 代碼,您會發現下一個聲明:
public class HashMap extends AbstractMap implements Map, Cloneable, Serializable
其中
K是此映射維護的鍵類型,
V - 映射值的類型。這是在您的代碼中使用 Integer 鍵和 String 值聲明 HashMap 的示例:
HashMap<Integer, String> myHashMap = new HashMap<Integer, String>();
哈希映射方法
這是 HashMap 方法的列表。
- Object get(Object key)返回指定鍵的值;
- Object put(Key k, Value v)將鍵值映射插入到map中;
- Object remove(Object key)從此映射中刪除指定鍵的映射(如果存在);
- void clear()從 HashMap 中移除所有鍵值對;
- 對象 clone()返回此 HashMap 實例的淺表副本,而不克隆鍵和值;
- boolean containsKey(Object key)如果在映射中找到指定的鍵,則返回 true,否則返回 false;
- boolean containsValue(Object Value)如果在映射中找到指定的鍵,則返回 true,否則返回 false;
- boolean isEmpty()如果地圖為空則返回 true,否則返回 false;
- Set keySet()返回從地圖中獲取的鍵的集合;
- int size()返回鍵值映射的數量;
- Collection values()返回地圖值的集合;
- Object remove(Object key)刪除指定鍵的鍵值對;
- void putAll(Map m)將地圖的所有元素複製到另一個地圖。
Java HashMap 示例
讓我們用 Java HashMap Example 創建一個程序來演示它是如何工作的:
import java.util.HashMap;
import java.util.Map;
import java.util.Iterator;
import java.util.Set;
public class HashMap {
public static void main(String[] args) {
{
// HashMap declaration
HashMap<Integer, String> myHashMap = new HashMap<Integer, String>();
//Adding elements into HashMap
myHashMap.put(7, "Johnny");
myHashMap.put(8, "Ivy");
myHashMap.put(1, "Rick");
myHashMap.put(4, "Stan");
myHashMap.put(3, "Kyle");
//print out the map content using Iterator
Set set = myHashMap.entrySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
Map.Entry mapEntry = (Map.Entry) iterator.next();
System.out.print("key: " + mapEntry.getKey() + " value: ");
System.out.println(mapEntry.getValue());
}
System.out.println("get an element from myHashMap via key and print the value out:");
System.out.println(myHashMap.get(8));
//print out hashMap on standard way:
System.out.println(myHashMap);
// Get values based on key
String var = myHashMap.get(2);
//here we'll get null, we don't have such a key
System.out.println("Value with key 2: " + var);
var = myHashMap.get(7);
System.out.println("Value with key 7: " + var);
// Remove values based on key
myHashMap.remove(4);
System.out.println("myHashMap after removing element:");
System.out.println(myHashMap);
myHashMap.clear();
System.out.println("myHashMap after total clearing:");
System.out.println(myHashMap);
}
}
}
程序運行結果:
key: 1 value: Rick
key: 3 value: Kyle
key: 4 value: Stan
key: 7 value: Johnny
key: 8 value: Ivy
get an element from myHashMap via key and print the value out:
Ivy
{1=Rick, 3=Kyle, 4=Stan, 7=Johnny, 8=Ivy}
Value with key 2: null
Value with key 7: Johnny
myHashMap after removing element:
{1=Rick, 3=Kyle, 7=Johnny, 8=Ivy}
myHashMap after total clearing:
{}
樹圖
Java中的TreeMap也實現了Map<Key,Value>接口,但它是基於紅黑樹數據結構的。樹由“節點”和連接節點的線——分支組成。“根”節點在樹的頂部。從根開始,可以有分支和節點。它是一個層次結構,你可能會想到這些節點作為根的“孩子”。子節點可以有自己的孩子 - 較低的節點。沒有孩子的節點稱為“端節點”或“葉”。二叉樹是一棵樹,其中每個節點都有零,一個, 或兩個孩子。二叉搜索樹是一種結構,其中每個內部節點存儲一個鍵,有時存儲一個關聯的值,並且有兩個不同的子樹(“左”和“右”)。自平衡二叉搜索樹是一種基於節點的二叉搜索樹,它在面對任意項目插入和刪除時自動保持其高度(根以下的最大層數)較小。紅黑樹是一棵平衡二叉樹,具有以下特性:
- 每個節點要么是紅色要么是黑色
- 根永遠是黑色的
- 每個葉子都是一個 NIL(有點空,空)節點,它是黑色的
- 如果一個節點是紅色的,它的孩子肯定是黑色的。
- 從節點到後代葉子的每條簡單路徑都包含相同數量的黑色節點。
一個 TreeMap 特徵
TreeMap 使用樹數據結構將鍵存儲為節點,並使用紅黑樹算法對鍵進行排序。因此,TreeMap 根據其鍵的自然順序對其條目進行排序。對於數字,自然是升序,對於字符串——字母順序。如果需要更改排序邏輯,可以使用比較器。以自然的方式對對象進行排序是 TreeMap 的一大優勢,以及使用不同的過濾器和條件查找某些對象。
樹圖方法
- Object get(Object key)返回對應key的值;
- Object put(Object key, Object value)將一個映射插入到一個映射中;
- 如果 TreeMap 包含此鍵,則Object remove(Object key)刪除此鍵的映射;
- boolean containsKey(Object key)如果此映射包含指定鍵的映射,則返回 true;
- boolean containsValue(Object value)如果 TreeMap 將一個或多個鍵映射到指定值,則返回 true;
- Object firstKey()返回排序映射中當前的第一個鍵;
- Object lastKey()返回排序映射中當前的最後一個鍵;
- void putAll(Map map)將指定地圖中的所有映射複製到地圖中;
- Set entrySet()返回映射的集合視圖
- int size()返回鍵值映射的數量
- Collection values()返回值的集合視圖
- 對象 clone()返回 TreeMap 的淺表副本
- void clear()從 TreeMap 中刪除所有映射
- SortedMap headMap(Object key_value)返回地圖中小於參數key_value部分的視圖
- Set keySet()返回樹圖中包含的鍵的集合視圖
- SortedMap subMap(K fromKey, K toKey)返回此映射部分的視圖,其鍵範圍從 fromKey(包含)到 toKey(不包含)
- Object firstKey()返回 TreeMap 中的第一個鍵。
樹圖示例
import java.util.TreeMap;
import java.util.Set;
import java.util.Iterator;
import java.util.Map;
public class TreeMapExample {
public static void main(String args[]) {
//TreeMap declaration
TreeMap<Integer, String> myTreeMap = new TreeMap<Integer, String>();
//put elements to TreeMap
myTreeMap.put(1, "Stuart");
myTreeMap.put(23, "Michael");
myTreeMap.put(7, "Johnny");
myTreeMap.put(5, "Ivy");
myTreeMap.put(2, "Alex");
//Display and print out myTreeMap using Iterator
Set set = myTreeMap.entrySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
Map.Entry myEntry = (Map.Entry) iterator.next();
System.out.print("key: " + myEntry.getKey() + " value: ");
System.out.println(myEntry.getValue());
}
//TreeMap printed in classical way
System.out.println(myTreeMap);
//removing an element with the key =2
myTreeMap.remove(2);
//myTreeMap after removing:
System.out.println(myTreeMap);
}
}
程序運行結果:
key: 1 value: Stuart
key: 2 value: Alex
key: 5 value: Ivy
key: 7 value: Johnny
key: 23 value: Michael
{1=Stuart, 2=Alex, 5=Ivy, 7=Johnny, 23=Michael}
{1=Stuart, 5=Ivy, 7=Johnny, 23=Michael}
鍊錶
LinkedHashMap 是一種結合了鍊錶和哈希映射的數據結構。的確,LinkedHashMap 擴展了HashMap 類並實現了Map 接口,但是鍊錶是什麼呢?LinkedHashMap 的聲明:
Map <Integer, String> linkedHashMap = new LinkedHashMap <Integer, String>();
這個新的linkedHashMap繼承了HashMap的屬性(如table、loadFactor、threshold、size、entrySet),還得到了兩個特殊的屬性:
- header 是雙向鍊錶的頭部。在初始化期間,它指示自己
- accessOrder 指示如何使用迭代器訪問元素。如果為真,則按照上次訪問的順序。如果為 false,訪問將按照插入元素的順序進行。
該鍊錶定義了迭代順序。通常,它是鍵插入映射的順序。
LinkedHashMap 方法
- Object get(Object key)返回指定鍵映射到的值,如果此映射不包含鍵的映射,則返回 null
- void clear()從地圖中刪除所有映射。
- boolean containsKey(Object key)如果指定元素由一個或多個鍵映射,則返回 true
- boolean removeEldestEntry(Map.Entry eldest)如果地圖從地圖中刪除其最老的條目,則返回 true
- Set<Map.Entry<K,V>> entrySet()返回此地圖中包含的映射的 Set 視圖
- void forEach(BiConsumer<? super K,? super V> action)對該映射中的每個條目執行給定的操作,直到處理完所有條目或操作引發異常。
- Object getOrDefault(Object key, V defaultValue)返回指定鍵映射到的值。如果映射不包含鍵的映射,則返回 defaultValue。
- Set<K> keySet()返回映射中包含的鍵的 Set 視圖
- boolean removeEldestEntry(Map.Entry<K,V> eldest)如果此映射應刪除其最舊的條目,則返回 true
- void replaceAll(BiFunction<? super K,? super V,? extends V> function) 用對該條目調用給定函數的結果替換每個條目值,直到所有條目都已處理或函數拋出異常。
- Collection<v>values()返回地圖中包含的值的集合視圖
LinkedHashMap 示例
import java.util.LinkedHashMap;
import java.util.Set;
import java.util.Iterator;
import java.util.Map;
public class HashLinkedListExample {
public static void main(String args[]) {
// LinkedHashMap Declaration
LinkedHashMap<Integer, String> myLinkedHashMap =
new LinkedHashMap<Integer, String>();
//Adding elements into LinkedHashMap
myLinkedHashMap.put(7, "Johnny");
myLinkedHashMap.put(12, "Rick");
myLinkedHashMap.put(1, "Kyle");
myLinkedHashMap.put(5, "Percy");
myLinkedHashMap.put(85, "Sebastian");
// Generate a Set of entries
Set set = myLinkedHashMap.entrySet();
// Display and print out the nodes of LinkedHashMap
Iterator iterator = set.iterator();
while(iterator.hasNext()) {
Map.Entry me = (Map.Entry)iterator.next();
System.out.print("key: "+ me.getKey() +
" value: "+me.getValue()+"\n");
}
//print out HashLinkedMap on standard way:
System.out.println(myLinkedHashMap);
myLinkedHashMap.put(21, "Ivy");
System.out.println(myLinkedHashMap);
myLinkedHashMap.remove(12);
System.out.println(myLinkedHashMap);
myLinkedHashMap.put(12, "Ronny");
System.out.println(myLinkedHashMap);
myLinkedHashMap.put(1, "Stan");
System.out.println(myLinkedHashMap);
}
}
在這裡,我們創建了一個新的 LinkedHashMap,添加了五個元素,然後使用迭代器以經典方式將其打印出來。如您所見,LinkedHashMap 維護插入順序。之後,我們從 Map 中刪除一個元素,然後添加新元素,然後再添加一個帶有鍵的元素,該元素已經在地圖上。它替換映射到此鍵的舊值。
程序運行結果:
key: 7 value: Johnny
key: 12 value: Rick
key: 1 value: Kyle
key: 5 value: Percy
key: 85 value: Sebastian
{7=Johnny, 12=Rick, 1=Kyle, 5=Percy, 85=Sebastian}
{7=Johnny, 12=Rick, 1=Kyle, 5=Percy, 85=Sebastian, 21=Ivy}
{7=Johnny, 1=Kyle, 5=Percy, 85=Sebastian, 21=Ivy}
{7=Johnny, 1=Kyle, 5=Percy, 85=Sebastian, 21=Ivy, 12=Ronny}
{7=Johnny, 1=Stan, 5=Percy, 85=Sebastian, 21=Ivy, 12=Ronny}
HashMap、TreeMap、LinkedHashMap比較
HashMap、TreeMap、LinkedHashMap是Map接口的實現。HashMap 和 LinkedHashMap 是哈希鍵的數據結構。TreeMap 使用其鍵的自然順序來組織搜索樹。
命令:
- HashMap 不維護任何順序。
- TreeMap 按鍵的升序對條目進行排序。
- LinkedHashMap 維護插入順序。
空鍵:
- HashMap 和 LinkedHashMap 允許有一個空鍵。
- LinkedHashMap 不允許空鍵,以防鍵使用自然順序或 Comparator 不支持對空鍵進行比較。
讓我們來看一個 Java 地圖示例,其中包含本文中討論的所有三種實現:
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.TreeMap;
public class CompMapImpl {
public static void main(String[] args) {
HashMap<Integer, String> hashMap = new HashMap<>();
TreeMap<Integer, String> treeMap = new TreeMap<>();
LinkedHashMap<Integer, String> linkedHashMap = new LinkedHashMap<>();
hashMap.put(5, "Ivy");
hashMap.put(null, "Joker");
hashMap.put(1, "First");
hashMap.put(2, "Kyle");
hashMap.put(-2, "Paul");
hashMap.put(3, "Sandy");
treeMap.put(5, "Ivy");
//treeMap.put(null,"Joker");
treeMap.put(1, "First");
treeMap.put(2, "Kyle");
treeMap.put(-2, "Paul");
treeMap.put(3, "Sandy");
linkedHashMap.put(5, "Ivy");
linkedHashMap.put(null, "Joker");
linkedHashMap.put(1, "First");
linkedHashMap.put(2, "Kyle");
linkedHashMap.put(-2, "Paul");
linkedHashMap.put(3, "Sandy");
System.out.println("HashMap");
System.out.println(hashMap);
System.out.println("TreeMap");
System.out.println(treeMap);
System.out.println("LinkedHashMap");
System.out.println(linkedHashMap);
LinkedHashMap<String, String> linkedHashMap1= new LinkedHashMap<> ();
linkedHashMap1.put(null, "Andy");
System.out.println(linkedHashMap1);
}
}
下面是運行這個程序的結果:
HashMap
{null=Joker, 1=First, -2=Paul, 2=Kyle, 3=Sandy, 5=Ivy}
TreeMap
{-2=Paul, 1=First, 2=Kyle, 3=Sandy, 5=Ivy}
LinkedHashMap
{5=Ivy, null=Joker, 1=First, 2=Kyle, -2=Paul, 3=Sandy}
{null=Andy}
可以看出,HashMap 中元素的順序並不明顯,treeMap 中靠鍵,LinkedHashMap 中靠插入順序。如果我們嘗試將空鍵放入 linkedHashMap,我們將得到 NullPointerException,但在 linkedHashMap1 中,鍵是 String,我們可以做到。哈希映射是最好的通用映射實現。它提供了最大的搜索速度、快速的存儲和檢索操作,但您應該記住它的混亂排序。鏈接的哈希映射繼承了 HashMap 的優點並獲得了鍵的順序。但是,它包含 linkedList,在內存方面相對昂貴。由於維護鍊錶,它在搜索方面比 HashMap 慢,並且在添加/刪除方面慢一點。樹圖存儲按升序排序的鍵。然而,
為了鞏固您所學的知識,我們建議您觀看我們的 Java 課程中的視頻課程
GO TO FULL VERSION