Java中的映射Map - 入門篇


前言

大家好啊,我是湯圓,今天給大家帶來的是《Java中的映射Map - 入門篇》,希望對大家有幫助,謝謝

簡介

前面介紹了集合List,這里開始簡單介紹下映射Map,相關類如下圖所示

集合

正文

Map是一種存儲鍵值對的數據集合,鍵以散列或者樹形結構進行存儲;

為什么會設計Map接口呢?

假設我們有一個員工類,里面有Id屬性和姓名等其他信息,現在我們把所有員工都存到List里,然后要找出Id為001的員工,你會發現,你需要從List中遍歷每個對象,然后取出Id進行比較;

你會發現這種查找法效率很低,有點殺雞用牛刀的感覺;

這時如果有一個集合類,可以以鍵值對映射的方式的存儲員工信息(Id作為鍵,員工信息作為值),那么就可以只遍歷鍵列表,然后進行比較;

你會發現這種查找法效率提高了很多,因為物盡其用了(比較的是Id,也只是取了Id,沒有浪費);

這就是Map接口的作用,可以根據某個鍵去查找對應的信息,有點類似於數據庫的設計。

Map的種類

Map主要有三種類型:HashMap(常用)、TreeMap(樹形結構)、LinkedHashMap(前兩者的結合)

我們先來看一下Map接口主要的幾個方法:

  • V put(K key, V value):往Map中添加鍵值對,其中key為鍵,value為值;如果key存在,則覆蓋原有的值;如果不存在,則新建鍵值對。
  • V get(Object key):從Map中查找鍵key對應的值,如果沒有,則返回null
  • default V getOrDefault(Object key, V defaultValue):從Map中查找鍵key對應的值,如果沒有,則返回第二個參數(設置的默認值);這里的修飾符default是用在接口方法中,表示這個方法在接口中已經實現了,子類可以不實現(Java8開始支持)
  • Set<K> keySet():返回Map中Key的集合;之所以返回Set,是因為Map中的key不能有重復,所以用Set最適合了
  • Collection<V> values():返回Map中Values的集合

下面我們簡單看下三者的區別

HashMap TreeMap LinkedHashMap
訪問速度 適中
元素是否有序 無序 有序,默認按key排序 有序,默認按插入的順序
適用場景 普通的插入,查詢(用的最多) 需要對key進行排序的場景(比如員工按年齡排序等) 需要保證查詢和插入順序一致的場景(類似隊列)

接下來我們以HashMap為例,來介紹Map接口

HashMap

HashMap內部是數組+鏈表的結構;

因為在添加鍵值對的時候,Key做了hash處理,然后按照hash值進行排列;

  • 如果hash值沒有重復,就按照數組的方式依次排列;
  • 如果hash值有重復的,就添加到已有的鍵值對后面(Java8以后是尾部插入),形成鏈表結構;

整體結構 如下圖所示

HashMap結構

這里只是簡單介紹,以后再深入了解

下面用代碼示范一下

// 鍵值對集合,鍵不可以重復
Map<String, Integer> map = new HashMap<>();
// 添加:首先會檢查對應的key是否存在,如果不存在,則新建鍵值對,然后填充;如果存在,則覆蓋已有的值
map.put("a", 1); // 這里的1會自動裝箱為Intege類型
// 查詢
int value1 = map.get("a");
int value2 = map.get("b"); 
System.out.println(map);

這里有個很有意思的現象,你覺得value2會是多少呢?

答案是多少都不是,因為程序運行到這一行就出錯了,報空指針異常

HashMap空指針異常

不應該返回null嗎?怎么會出錯?

這里涉及到拆箱和裝箱的問題,上面我們在添加put的時候,int 1自動裝箱為Integer;

然后在獲取get的時候,對應的也是要進行拆箱的,將Integer轉為int;

但是由於獲取的value = null,所以就相當於對null進行拆箱,結果就報錯了。

解決辦法就是嚴格按照Map的類型信息進行添加和獲取;

將上面的代碼加以修改,如下所示

// 鍵值對集合,鍵不可以重復
Map<String, Integer> map = new HashMap<>();
// 添加:首先會檢查對應的key是否存在,如果不存在,則新建鍵值對,然后填充;如果存在,則覆蓋已有的值
map.put("a", 1); // 這里的1會自動裝箱為Intege類型
// 查詢
Integer value1 = map.get("a");
Integer value2 = map.get("b");
System.out.println(map);

此時value2就等於null了。

關於自動裝箱和拆箱,網上資源很多,這里就不再細說了

TreeMap

TreeMap在插入的時候,可以按照鍵的順序進行排序

它適合用在排序比較多的場景,性能會比HashMap差一些

LinkedHashMap

LinkedHashMap擁有HashMap的大部分優點,且保證了插入的順序,使得在查詢的時候,可以按照插入的順序依次讀取

三者的排序比較

下面用代碼演示一下,依次插入100個數,看看他們分別是怎么排序的

HashMapDemo.java

public class HashMapDemo {
    public static void main(String[] args) {
        // 鍵值對集合,鍵不可以重復
        Map<String, Integer> map = new HashMap<>();
        // 倒序插入100個數
        int i =100;
        while (i-->0){
            map.put(""+i, i);
        }
        // 查詢
        for (String str :
                map.keySet()) {
            // 這里會亂序輸出
            System.out.println(str);
        }
    }
}

輸出如下所示:很亂

HashMap輸出亂序

TreeMapDemo.java


public class MapDemo {
    public static void main(String[] args) {
       
        // TreeMap
        Map<String, Integer> map1 = new TreeMap<>();
        // 連續倒序插入100個數
        int k =100;
        while (k-->0){
            map1.put(""+k, k);
        }
        // 查詢
        for (String str :
                map1.keySet()) {
            // 這里會正序輸出
            System.out.println(str);
        }
    }
}

輸出如下所示:

TreeMap輸出正序

細心的你們,應該會發現上面的輸出有點別致

那是因為這里的鍵key(0~99)其實不是整型,而是字符串類型,所以排序按照字符串的升序來排,才會出現如圖所示的結果

(建議實際場景不要這樣搞,容易出事,字符串盡量不要用純數字,而是要跟字母做拼接;)

正確的做法是key=“a”+i,這種方式

LinkedHashMapDemo.java


public class MapDemo {
    public static void main(String[] args) {
        // LinkedHashMap
        Map<String, Integer> map2 = new LinkedHashMap<>();
        // 倒序插入100個數
        int j =100;
        while (j-->0){
            map2.put("a"+j, j);
        }
        for (String str :
                map2.keySet()) {
            // 這里按照插入的順序依次輸出
            System.out.println(map2.get(str));
        }
    }
}

輸出如下所示:

LinkedHashMap按插入順序輸出

總結

Map一般用到的有HashMap,TreeMap,LinkedHashMap,當然還有並發相關的,這里入門級別的先不涉及(比如ConcurrentHashMap)

  • HashMap的插入和訪問都很快,但是內部是無序排列

  • TreeMap的插入和訪問都很慢,但是內部是有序排列,默認按key升序排列

  • LinkedHashMap擁有HashMap的大部分優點,而且還可以按照元素插入的順序來訪問元素,但是性能會比HashMap差

后記

最后,感謝大家的觀看,謝謝


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM