java HashMap類,底層自學自看 筆記(實時更新)
阿新 • • 發佈:2018-12-05
提示:本文章是基於jdk1.7,對於一些常見類底層學習的公開筆記,學藝不精,發現錯誤請評論提出。
一:實現的介面,繼承的類
繼承1:AbstractMap:是一個抽象類,他實現了Map介面。對Map介面的一些方法進行了實現。
2:Map<K,V>:是一個介面,規範map集合需要實現的方法
3:Cloneable:克隆介面,無任何方法引數,但卻實現了一個隱藏機制,無需呼叫構造器就可以建立物件的克隆機制。
4:Serializable:序列化
二:擁有的屬性
1
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
注:預設初始化容量屬性,意味著HashMap的預設初始化容量為16
2
static final int MAXIMUM_CAPACITY = 1 << 30;
注:最大容量:1 073 741 824
3
static final float DEFAULT_LOAD_FACTOR = 0.75f;
注:儲存因子具體值。儲存因子越大,對系統空間利用率越高,但越容易因為hash衝突,反之亦然。因此取了一箇中間值。
4
static final Entry<?,?>[] EMPTY_TABLE = {}; transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
注:當新增等操作會用到,日後附帶程式碼說明,jdk標明的註釋,依舊解釋不清晰
5
transient int size;
int threshold;
注:長度,一個可以被序列化,一個不可以,後者是hashmap空間的長度,前者則是資料的長度。
6
final float loadFactor;//儲存因子
7
transient int modCount;
注:改值記錄了這個物件被操作的次數。即使map執行了clear方法,你個數值也不會被清零。假如克隆這個物件而新生成的物件,那麼新物件的這個屬性會是0;
8
static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE; 譯:可替換的程式碼值。也就是map裡連結串列的最大個數。
9
//內部類 沒有太高深的邏輯,底層也進入到了c語言,所以就做個簡單的分析
//儲存VM啟動後無法初始化的值。
private static class Holder {
static final int ALTERNATIVE_HASHING_THRESHOLD;
static {
String altThreshold = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction(
"jdk.map.althashing.threshold"));
//初始化的時候int預設為0,altThreshold也是0
int threshold;
try {
threshold = (null != altThreshold)
? Integer.parseInt(altThreshold)
: ALTERNATIVE_HASHING_THRESHOLD_DEFAULT;
//顯然doPrivileged方法並不能保證一定會讀出來這個0的資料
// disable alternative hashing if -1
if (threshold == -1) {
threshold = Integer.MAX_VALUE;
}
if (threshold < 0) {
throw new IllegalArgumentException("value must be positive integer.");
}
} catch(IllegalArgumentException failed) {
throw new Error("Illegal value for 'jdk.map.althashing.threshold'", failed);
}
ALTERNATIVE_HASHING_THRESHOLD = threshold;
}
}
注:那麼這個內部類的意義是什麼?其實 沒什麼高深的東西,就類似讀取配置檔案,初始化這個工具屬性。當長度發生改變時或者克隆都會用到。具體初始化了什麼還真不知道
10
我決定把這個內部類提前,因為這個比較重要,不先寫出來梳理的不順暢
//HashMap的核心這個表明了HashMap的儲存方式
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;
int hash;
//所說的連結串列,不過是一個大腦虛擬的,方便理解的一種形式
Entry(int h, K k, V v, Entry<K,V> n) {
value = v;
next = n;
key = k;
hash = h;
}
public final K getKey() {
return key;
}
public final V getValue() {
return value;
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry e = (Map.Entry)o;
Object k1 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
Object v1 = getValue();
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2)))
return true;
}
return false;
}
public final int hashCode() {
return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
}
public final String toString() {
return getKey() + "=" + getValue();
}
void recordAccess(HashMap<K,V> m) {
}
void recordRemoval(HashMap<K,V> m) {
}
}
注:這雖然是核心,但卻沒什麼特殊的東西,沒有什麼高深的邏輯和技術。
當執行put方法是,其實就是在陣列的下一個索引上增加一個這個物件,next就是儲存的下一個這個物件。
具體的實現會慢慢以展現程式碼梳理。
2018年11月14日10:00:00,第一次更新。邊工作邊看底層,更新速度不會很快
2018年11月15日15:19:39,第二次更新