天天看點

Java集合(7)--Map接口的實作類HashMap、LinkHashMap、TreeMap和Properties

文章目錄

    • HashMap類
    • LinkedHashMap類
    • TreeMap類
    • Hashtable類
    • Properties類

HashMap類

1、HashMap類概述

HashMap是 Map 接口使用頻率最高的實作類,允許使用null鍵和null值,與HashSet一樣,不保證映射的順序。

所有的key構成的集合是Set:無序的、不可重複的。是以,key所在的類要重寫

equals()

hashCode()

所有的value構成的集合是Collection:無序的、可重複的。是以,value所在的類

要重寫

equals()

一個

key-value

構成一個entry,所有的entry構成的集合是Set:無序的、不可重複的。

HashMap判斷兩個 key 相等的标準:兩個 key 通過

equals()

方法傳回 true,

hashCode()

值也相等。

HashMap判斷兩個 value 相等的标準:兩個 value 通過

equals()

方法傳回 true。

2、HashMap的存儲結構(底層實作原理)

(以JDK1.7說明)

在執行個體化以後,底層就建立了長度為16的一維數組

Entry[] table

首先,調用key1所在類的

hashCode()

計算key1哈希值,此哈希值經過某種算法計算以後,得到在

Entry[]

數組中的存放位置。

如果此位置上的資料為空,此時的

key1-value1

添加成功。----情況1

如果此位置上的資料不為空(意味着此位置上存在一個或多個資料(以連結清單形式存在)),則繼續比較key1和已經存在的一個或多個資料的哈希值:

如果key1的哈希值與已經存在的資料的哈希值都不相同,此時

key1-value1

添加成功。----情況2

如果key1的哈希值和已經存在的某一個資料

key2-value2

的哈希值相同,繼續比較:

調用key1所在類的

equals(key2)

如果

equals()

傳回false:此時

key1-value1

添加成功。----情況3

如果

equals()

傳回true:使用value1替換value2。

補充:關于情況2和情況3,此時

key1-value1

和原來的資料以連結清單的方式存儲。

在不斷的添加過程中,會涉及到擴容問題,預設的擴容方式:擴容為原來容量的2倍,并将原有的資料複制過來。

JDK1.8相較于JDK1.7在底層實作方面的不同:

new HashMap()

,底層還沒有建立一個長度為16的數組

②JDK1.8底層的數組是:

Node[]

,而非

Entry[]

③首次調用

put()

方法時,底層才建立長度為16的數組

Node[]

④形成連結清單結構時,新添加的key-value對在連結清單的尾部(七上八下)

⑤JDK1.7底層結構隻有“數組+連結清單”,JDK1.8中底層結構為“數組+連結清單+紅黑樹”。

當數組的某一個索引位置上的元素以連結清單形式存在的資料個數>8且目前數組的長度>64時,此時此索引位置上的所有資料改為使用紅黑樹存儲。

Java集合(7)--Map接口的實作類HashMap、LinkHashMap、TreeMap和Properties
Java集合(7)--Map接口的實作類HashMap、LinkHashMap、TreeMap和Properties

3、HashMap源碼中的重要常量

DEFAULT_INITIAL_CAPACITY

: HashMap的預設容量,16

MAXIMUM_CAPACITY

: HashMap的最大支援容量,2^30

DEFAULT_LOAD_FACTOR

:HashMap的預設加載因子,0.75

TREEIFY_THRESHOLD

:Bucket中連結清單長度大于該預設值8,轉化為紅黑樹

UNTREEIFY_THRESHOLD

:Bucket中紅黑樹存儲的Node小于該預設值6,轉化為連結清單

MIN_TREEIFY_CAPACITY

:桶中的Node被樹化時最小的hash表容量。(當桶中Node的數量大到需要變紅黑樹時,若hash表容量小于MIN_TREEIFY_CAPACITY時,此時應執行resize擴容操作這個MIN_TREEIFY_CAPACITY的值至少是TREEIFY_THRESHOLD的4倍為64。)

table

:存儲元素的數組,總是2的n次幂

entrySet

:存儲具體元素的集

size

:HashMap中存儲的鍵值對的數量

modCount

:HashMap擴容和結構改變的次數。

threshold

:擴容的臨界值,=容量*填充因子

loadFactor

:填充因子

LinkedHashMap類

LinkedHashMap 是 HashMap 的子類

在HashMap存儲結構的基礎上,使用了一對雙向連結清單來記錄添加元素的順序

與LinkedHashSet類似,LinkedHashMap 可以維護 Map 的疊代順序:疊代順序與 Key-Value 對的插入順序一緻

Java集合(7)--Map接口的實作類HashMap、LinkHashMap、TreeMap和Properties

TreeMap類

1、TreeMap類概述

TreeMap存儲 Key-Value 對時,需要根據 key 進行排序。TreeMap 可以保證所有的 Key-Value 處于有序狀态。

TreeSet底層使用紅黑樹結構存儲資料。

TreeMap 的 Key 的排序:

①自然排序:TreeMap 的所有的 Key 必須實作 Comparable 接口,而且所有

的 Key 應該是同一個類的對象,否則将會抛出 ClasssCastException。

②定制排序:建立 TreeMap 時,傳入一個 Comparator 對象,該對象負責對

TreeMap 中的所有 key 進行排序,此時不需要 Map的Key實作Comparable接口。

TreeMap判斷兩個key相等的标準:兩個key通過compareTo()方法或者compare()方法傳回0。

2、自然排序

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

/**
 * @Author: Yeman
 * @Date: 2021-09-22-22:59
 * @Description:
 */

class user implements Comparable{
    String name;
    int age;

    public user(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "user{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Object o) {
        if (o instanceof user){
            user other = (user) o;
            Integer nameResult = this.name.compareTo(other.name);
            if (nameResult == 0){
                return Integer.compare(this.age,other.age);
            }else return nameResult;
        }else throw new RuntimeException("類型不比對");
    }
}


public class TreeMapTest {
    public static void main(String[] args) {
        Map map = new TreeMap();
        map.put(new user("Tom",22),1);
        map.put(new user("Jim",18),2);
        map.put(new user("Marry",20),3);
        map.put(new user("Lily",16),4);
        map.put(new user("Tom",18),5);

        Set set = map.entrySet();
        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}
           
Java集合(7)--Map接口的實作類HashMap、LinkHashMap、TreeMap和Properties

3、定制排序

import java.util.*;

/**
 * @Author: Yeman
 * @Date: 2021-09-22-22:59
 * @Description:
 */

class user {
    String name;
    int age;

    public user(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "user{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class TreeMapTest {
    public static void main(String[] args) {
        Comparator comparator = new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                if (o1 instanceof user && o2 instanceof user) {
                    user user1 = (user) o1;
                    user user2 = (user) o2;
                    Integer nameResult = user1.name.compareTo(user2.name);
                    if (nameResult == 0) return Integer.compare(user1.age, user2.age);
                    else return nameResult;
                } else throw new RuntimeException("類型不比對");
            }
        };

        Map map = new TreeMap(comparator);
        map.put(new user("Tom",22),1);
        map.put(new user("Jim",18),2);
        map.put(new user("Marry",20),3);
        map.put(new user("Lily",16),4);
        map.put(new user("Tom",18),5);

        Set set = map.entrySet();
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}
           
Java集合(7)--Map接口的實作類HashMap、LinkHashMap、TreeMap和Properties

Hashtable類

Hashtable是個古老的 Map 實作類,JDK1.0就提供了。不同于HashMap,

Hashtable是線程安全的。

Hashtable實作原理和HashMap相同,功能相同。底層都使用哈希表結構,查詢

速度快,很多情況下可以互用。

與HashMap不同,Hashtable 不允許使用 null 作為 key 和 value。

與HashMap一樣,Hashtable 也不能保證其中 Key-Value 對的順序。

Hashtable判斷兩個key相等、兩個value相等的标準,與HashMap一緻。

Properties類

Properties 類是 Hashtable 的子類,該對象用于處理屬性檔案,由于屬性檔案裡的 key、value 都是字元串類型,是以 Properties 裡的 key 和 value 都是字元串類型

存取資料時,建議使用

setProperty(String key,String value)

方法和

getProperty(String key)

方法

Properties pros = new Properties();
pros.load(new FileInputStream("jdbc.properties"));
String user = pros.getProperty("user");
System.out.println(user);