構(gòu)造函數(shù)
變量解釋
- capacity杆融,表示的是hashmap中桶的數(shù)量楞卡,初始化容量initCapacity為16,第一次擴(kuò)容會(huì)擴(kuò)到64脾歇,之后每次擴(kuò)容都是之前容量的2倍蒋腮,所以容量每次都是2的次冪
- loadFactor,負(fù)載因子藕各,衡量hashmap一個(gè)滿的程度池摧,初始默認(rèn)為0.75
- threshold,hashmap擴(kuò)容的一個(gè)標(biāo)準(zhǔn)激况,每當(dāng)size大于這個(gè)標(biāo)準(zhǔn)時(shí)就會(huì)進(jìn)行擴(kuò)容操作,threeshold等于capacity*loadfacfactor
HashMap(int initialCapacity, float loadFactor)
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegalinitial capacity: " +initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
//構(gòu)造函數(shù)前面都很容易理解作彤,無非是設(shè)置正確的initialCapacity和loadFactor
//最后一行調(diào)用的tableSizeFor(initialCapacity);如下
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
tableSizeFor(...)方法的作用在于找到大于等于initialCapacity的最小的2的冪。n右移一位再同自身進(jìn)行或操作使得n的最高位和最高位的下一位都為1.
n |= n >>> 1;
比如n=9乌逐,則n=1001(2)竭讳,n-1=100
1001
0100
-----
1100
這是因?yàn)榛虿僮鞯囊鬄橄嗤簧现灰嬖?則結(jié)果為1,全為0結(jié)果才為0.一個(gè)數(shù)最高位為1黔帕,右移一位后的數(shù)最高位也為1代咸,不論相對(duì)應(yīng)的位上另一個(gè)數(shù)是多少結(jié)果依舊為1.
而對(duì)于n |= n >>> 2
n的最高位及其下一位都為1,右移兩位后再進(jìn)行或操作將使得得到的n的前4位都為1成黄,類似的n |= n >>> 4
使得前8位為1呐芥,n |= n >>> 8
使得前16位為1。當(dāng)然并不是說該方法調(diào)用下來就會(huì)使得返回的值是一個(gè)32位都為1的數(shù)字奋岁,這是因?yàn)楫?dāng)右移的位數(shù)操作實(shí)際的有效位數(shù)后是不會(huì)對(duì)數(shù)字產(chǎn)生任何變化的思瘟。
以n=9為例,在進(jìn)過兩次右移后n=1111(2)
00000000000000000000000000001111 n (int 32位)
00000000000000000000000000000000 n>>>4
--------------------------------
00000000000000000000000000001111
當(dāng)n右移4位后全部變成了0,使得結(jié)果不會(huì)發(fā)生任何變化闻伶,后面的n |= n >>> 8等等也一樣
在最后返回的時(shí)候做了一個(gè)判斷(n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1
滨攻,正常來說返回的是一個(gè)n+1,在前面的操作中已經(jīng)將前幾位有效的數(shù)字變成了1(n=1111),這里加1使得n=10000(2)光绕,即變?yōu)榇笥诘扔趇nitialCapacity的最小的2的冪女嘲,到這里貌似就差不多了,但是在tableSizeFor(...)
方法的第一句有一個(gè)減法操作int n = cap - 1;
這是為什么呢诞帐?這里減1實(shí)際上是為處理傳入的數(shù)本身就是2的冪的情況欣尼。比如我傳入的是n=8=1000(2),如果不進(jìn)行減1操作停蕉,得到的則是n=10000(2)=16愕鼓,實(shí)際上我需要的就是8.
HashMap(Map<? extends K, ? extends V> m)
public HashMap(Map<? extends K, ? extends V> m) {
this.loadFactor = DEFAULT_LOAD_FACTOR;
putMapEntries(m, false);
}
這個(gè)構(gòu)造函數(shù)主要是用一個(gè)已有的map來構(gòu)造一個(gè)新的HashMap,這里主要在于putMapEntries(m, false);
中慧起。
final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
int s = m.size();
if (s > 0) {
if (table == null) { // pre-size
float ft = ((float)s / loadFactor) + 1.0F;
int t = ((ft < (float)MAXIMUM_CAPACITY) ?
(int)ft : MAXIMUM_CAPACITY);
if (t > threshold)
threshold = tableSizeFor(t);
}
else if (s > threshold)
resize();
for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
K key = e.getKey();
V value = e.getValue();
putVal(hash(key), key, value, false, evict);
}
}
}
前面幾行是做容錯(cuò)判斷菇晃,當(dāng)table沒有初始化或者傳入的map容量大于當(dāng)前map的閾值(threshold),都需要重新進(jìn)行設(shè)置蚓挤。從for循環(huán)開始則是將傳入的map的值插入到當(dāng)前map中磺送。