文章目錄
-
- 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時,此時此索引位置上的所有資料改為使用紅黑樹存儲。
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 對的插入順序一緻
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());
}
}
}
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());
}
}
}
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);