CodeGym /Java Blog /Toto sisi /Java 中的地圖接口
John Squirrels
等級 41
San Francisco

Java 中的地圖接口

在 Toto sisi 群組發布

什麼是 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工作的主要原理:散列

要了解什麼是哈希圖及其工作原理,讓我們先談談哈希和哈希函數。哈希函數只是數學意義上的函數。所以有一些輸入值(一個對象,一段數據)並且函數使用適當的規則將其轉換為輸出值 - 哈希。哈希通常是適當長度的十六進制數。轉換過程的規則可能不同,但都遵循以下原則:
  1. 特定的輸入(對象)具有特定的哈希碼。
  2. 如果兩個對象相等,則它們的哈希碼也相等。反之則不然。
  3. 如果哈希碼不同,則對象肯定不相等。
  4. 有時不同的對象可以有相同的散列碼。這是一個不太可能發生的事件,稱為“碰撞”,高質量的哈希函數應該將碰撞的可能性降到最低。
在 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 課程中的視頻課程
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION