Java 基礎(Map)


一: Map: 雙列數據,存儲 key-value 對的數據 ---類似於高中的函數: y = f(×)

  1. HashMap: 作為 Map 的主要實現類; 線程不安全的,效率高; 存儲null的key和value
    1.1 LinkedHashMap: 保證在遍歷map元素時,可以按照添加的順序實現遍歷。
    原因:在原有的HashMap底層結構基礎上,添加了一對指針,指向前一個和后一個元素。對於頻繁的遍歷操作,此類執行效率高於HashMap。

  2. TreeNMap: 保證按照添加的 key-value 對進行排序, 實現排序遍歷。此時考慮key的自然排序或定制排序。底層采用紅黑樹的存儲結構,有序,查詢速度比 List 快。

  3. Hashtable:作為古老的實現類; 線程安全的,效率低;不能存儲null的key和value
    3.1 Properties: 常用來處理配置文件。key和value都是String類型

HashMap的底層: 數組+鏈表 (jdk7及之前)
數組+鏈表+紅黑樹 (jdk 8)

二:Map結構的理解

Map中的 Key: 無序的、不可重復的,使用 Set 存儲所有的 key ---> key 所在的類要重寫 equals() 和 hashCode() (以 HashMap為例)
Map中的 value: 無序的、可重復的,使用 Collection 存儲所有的 value ---> value 所在的類要重寫 equals()
一個鍵值對: key-value 構成了一個 Entry 對象。
Map 中的 entry: 無序的、不可重復的,使用 Set 存儲所有的 entry

三: HashMap的底層實現原理 以jdk7為例說明:

HashMap map = new HashMap():
在實例化以后,底層創建了長度是16的一維數組Entry[] table
....可能已經執行過多次put...
map.put( key1 , value1):
首先,調用 key1 所在類的 hashCode() 計算 key1 哈希值,此哈希值經過某種算法計算以后,得到在 Entry 數組中的存放位置。

  1. 如果此位置上的數據為空,此時的 key1-value1 添加成功。----情況1
  2. 如果此位置上的數據不為空,(意味着此位置上存在一個或多個數據(以鏈表形式存在)),比較 key1 和已經存在的一個或多個數據的哈希值:
    2.1 如果 key1 的哈希值與已經存在的數據的哈希值都不相同,此時 key1-value1 添加成功。----情況2
    2.2 如果 key1 的哈希值和已經存在的某一個數據(key2-value2)的哈希值相同,繼續比較: 調用 key1 所在類的 equals(key2)
    2.2.1 如果 equals() 返回 false: 此時key1-value1添加成功。----情況3
    2.2.2 如果 equals() 返回 true: 使用 value1 替換 value2 。

補充: 關於情況2和情況3:此時 key1-value1 和原來的數據以鏈表的方式存儲。

在不斷的添加過程中,會涉及到擴容問題,當超出臨界值(且要存放的位置非空)時,擴容。默認的擴容方式: 擴容為原來容量的2倍,並將原有的數據復制過來。

jdk8 相較於 jdk7 在底層實現方面的不同:

  1. new HashMap(): 底層沒有創建一個長度為16的數組
  2. jdk8底層的數組是: Node[],而非 Entry[]
  3. 首次調用put()方法時,底層創建長度16的數組
  4. jdk7底層結構只有: 數組+鏈表。jdk8 中底層結構: 數組+鏈表+紅黑樹。
    當數組的某一個索引位置上的元素以鏈表形式存在的數據個數 > 8 且當前數組的長度 > 64 時,此時此索引位置上的所有數據改為使用紅黑樹存儲。

DEFAULT_INITIAL_CAPACITY: HashMap的默認容量,16
DEFAULT_LOAD_FACTOR: HashMap的默認加載因子: 0.75
threshold: 擴容的臨界值,=容量*填充因子: 16 * 0.75 => 12
TREEIFY_THRESHOLD: Bucket 中鏈表長度大於該默認值,轉化為紅黑樹:8
MIN_TREEIFY_CAPACITY: 桶中的 Node 被樹化時最小的 hash 表容量:64

package com.klvchen.java;

import org.junit.Test;

import java.util.*;

public class MapTest {

    @Test
    public void test5(){
        Map map = new HashMap();
        map.put("AA", 123);
        map.put(45, "123");
        map.put("BB", 56);

        //遍歷所有的key集:keySet()
        Set set = map.keySet();
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

        System.out.println("--------------------");
        //遍歷所有的 value集:values()
        Collection values = map.values();
        for (Object obj : values) {
            System.out.println(obj);
        }
        System.out.println("--------------------");
        //遍歷所有的 key-value
        //方式一: entrySet()
        //entrySet():
        Set entrySet = map.entrySet();
        Iterator iterator1 = entrySet.iterator();
        while (iterator1.hasNext()) {
            Object obj = iterator1.next();
            //entrySet 集合中的元素都是entry
            Map.Entry entry = (Map.Entry) obj;
            System.out.println(entry.getKey() + " -------> " + entry.getValue());

        }

        //方式二
        Set keySet = map.keySet();
        Iterator iterator2 = keySet.iterator();
        while (iterator2.hasNext()) {
            Object key = iterator2.next();
            Object value = map.get(key);
            System.out.println(key + " ===== " + value);
        }
    }

    @Test
    public void test4(){
        Map map = new HashMap();
        map.put("AA", 123);
        map.put(45, "123");
        map.put("BB", 56);

        //Object get(Object key)
        System.out.println(map.get(45));

        //conainsKey(Oject key)
        boolean isExist = map.containsKey("BB");
        System.out.println(isExist);

        isExist = map.containsKey(123);
        System.out.println(isExist);

        map.clear();

        System.out.println(map.isEmpty());
    }

    @Test
    public void test3(){
        Map map = new HashMap();
        //添加
        map.put("AA", 123);
        map.put(45, 123);
        map.put("BB", 56);
        //修改
        map.put("AA", 87);

        System.out.println(map);

        Map map1 = new HashMap();
        map1.put("CC", 123);
        map1.put("DD", 123);
        map.putAll(map1);

        System.out.println(map);

        //remove(Object key)
        Object value = map.remove("CC");
        System.out.println(value);
        System.out.println(map);

        //clear()
        map.clear();//與 map = null 操作不同
        System.out.println(map.size());
        System.out.println(map);
    }

    @Test
    public void test2(){
        Map map = new HashMap();

        map.put(123, "AA");
        map.put(345, "BB");
        map.put(12, "CC");

        System.out.println(map);
    }

    @Test
    public void test1(){
        Map map = new HashMap();
        //map = new Hashtable();
        map.put(null, 123);

    }
}

TreeMap

package com.klvchen.java;

import org.junit.Test;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

public class TreeMapTest {

    @Test
    public void test1(){
        TreeMap map = new TreeMap();
        User u1 = new User("Tom", 23);
        User u2 = new User("Jerry", 32);
        User u3 = new User("Jack", 20);
        User u4 = new User("Rose", 18);

        map.put(u1, 98);
        map.put(u2, 89);
        map.put(u3, 76);
        map.put(u4, 100);

        Set entrySet = map.entrySet();
        Iterator iterator1 = entrySet.iterator();
        while (iterator1.hasNext()) {
            Object obj = iterator1.next();
            //entrySet集合中的元素都是 entry
            Map.Entry entry = (Map.Entry) obj;
            System.out.println(entry.getKey() + " -----> " + entry.getValue());
        }

    }
}


免責聲明!

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



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