【81期】面試官:說(shuō)說(shuō)HashMap 中的容量與擴(kuò)容實(shí)現(xiàn)
閱讀本文大概需要 12?分鐘。
來(lái)自:cnblogs.com/youzhibing/p/11833040.html
高手過(guò)招,招招致命
/**
?*?數(shù)組
?*/
transient?Node[]?table;
/**
?*?鏈表結(jié)構(gòu)
?*/
static?class?Node<K,V>?implements?Map.Entry<K,V>?{
????final?int?hash;
????final?K?key;
????V?value;
????Node?next;
????Node(int?hash,?K?key,?V?value,?Node?next)?{
????????this.hash?=?hash;
????????this.key?=?key;
????????this.value?=?value;
????????this.next?=?next;
????}
????public?final?K?getKey()????????{?return?key;?}
????public?final?V?getValue()??????{?return?value;?}
????public?final?String?toString()?{?return?key?+?"="?+?value;?}
????public?final?int?hashCode()?{
????????return?Objects.hashCode(key)?^?Objects.hashCode(value);
????}
????public?final?V?setValue(V?newValue)?{
????????V?oldValue?=?value;
????????value?=?newValue;
????????return?oldValue;
????}
????public?final?boolean?equals(Object?o)?{
????????if?(o?==?this)
????????????return?true;
????????if?(o?instanceof?Map.Entry)?{
????????????Map.Entry,?>?e?=?(Map.Entry,?>)o;
????????????if?(Objects.equals(key,?e.getKey())?&&
????????????????Objects.equals(value,?e.getValue()))
????????????????return?true;
????????}
????????return?false;
????}
}
/**
?*?紅黑樹結(jié)構(gòu)
?*/
static?final?class?TreeNode<K,V>?extends?LinkedHashMap.Entry<K,V>?{
????TreeNode?parent;??//?red-black?tree?links
????TreeNode?left;
????TreeNode?right;
????TreeNode?prev;????//?needed?to?unlink?next?upon?deletion
????boolean?red;
????...

斗智斗勇,見招拆招
問(wèn)題 1:table 的初始化
/**
?*?構(gòu)造方法?1
?*
?*?通過(guò)?指定的?initialCapacity?和?loadFactor?實(shí)例化一個(gè)空的?HashMap?對(duì)象
?*/
public?HashMap(int?initialCapacity,?float?loadFactor)?{
????if?(initialCapacity?0)
????????throw?new?IllegalArgumentException("Illegal?initial?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)造方法?2
?*
?*?通過(guò)指定的?initialCapacity?和?默認(rèn)的?loadFactor(0.75)?實(shí)例化一個(gè)空的?HashMap?對(duì)象
?*/
public?HashMap(int?initialCapacity)?{
????this(initialCapacity,?DEFAULT_LOAD_FACTOR);
}
/**
?*?構(gòu)造方法?3
?*
?*?通過(guò)默認(rèn)的?initialCapacity?和?默認(rèn)的?loadFactor(0.75)?實(shí)例化一個(gè)空的?HashMap?對(duì)象
?*/
public?HashMap()?{
????this.loadFactor?=?DEFAULT_LOAD_FACTOR;?//?all?other?fields?defaulted
}
/**
?*
?*?構(gòu)造方法?4
?*?通過(guò)指定的?Map?對(duì)象實(shí)例化一個(gè)?HashMap?對(duì)象
?*/
public?HashMap(Map?extends?K,???extends?V>?m)?{
????this.loadFactor?=?DEFAULT_LOAD_FACTOR;
????putMapEntries(m,?false);
}
Map ?map?=?new?HashMap();
map.put("name",?"張三");
map.put("age",?21);
//?后續(xù)操作
...

/**
?*?Initializes?or?doubles?table?size.??If?null,?allocates?in
?*?accord?with?initial?capacity?target?held?in?field?threshold.
?*?Otherwise,?because?we?are?using?power-of-two?expansion,?the
?*?elements?from?each?bin?must?either?stay?at?same?index,?or?move
?*?with?a?power?of?two?offset?in?the?new?table.
?*
?*?@return?the?table
?*/
final?Node[]?resize()?{
????Node[]?oldTab?=?table;????????????????????//?第一次?put?的時(shí)候,table?=?null
????int?oldCap?=?(oldTab?==?null)???0?:?oldTab.length;?//?oldCap?=?0
????int?oldThr?=?threshold;????????????????????????//?threshold=0,?oldThr?=?0
????int?newCap,?newThr?=?0;
????if?(oldCap?>?0)?{????//?條件不滿足,往下走
????????if?(oldCap?>=?MAXIMUM_CAPACITY)?{
????????????threshold?=?Integer.MAX_VALUE;
????????????return?oldTab;
????????}
????????else?if?((newCap?=?oldCap?<1)??????????????????oldCap?>=?DEFAULT_INITIAL_CAPACITY)
????????????newThr?=?oldThr?<1;?//?double?threshold
????}
????else?if?(oldThr?>?0)?//?initial?capacity?was?placed?in?threshold
????????newCap?=?oldThr;
????else?{???????????????//?zero?initial?threshold?signifies?using?defaults?走到這里,進(jìn)行默認(rèn)初始化
????????newCap?=?DEFAULT_INITIAL_CAPACITY;????//?DEFAULT_INITIAL_CAPACITY?=?1?<4?=?16,?newCap?=?16;
????????newThr?=?(int)(DEFAULT_LOAD_FACTOR?*?DEFAULT_INITIAL_CAPACITY);????//?newThr?=?0.75?*?16?=?12;
????}
????if?(newThr?==?0)?{????//?條件不滿足
????????float?ft?=?(float)newCap?*?loadFactor;
????????newThr?=?(newCap?float)MAXIMUM_CAPACITY??
??????????????????(int)ft?:?Integer.MAX_VALUE);
????}
????threshold?=?newThr;????????//?threshold?=?12;?重置閥值為12
????@SuppressWarnings({"rawtypes","unchecked"})
????????Node[]?newTab?=?(Node [])new?Node[newCap];?????//?初始化?newTab,?length?=?16;
????table?=?newTab;????????????//?table?初始化完成,?length?=?16;
????if?(oldTab?!=?null)?{????//?此時(shí)條件不滿足,后續(xù)擴(kuò)容的時(shí)候,走此if分支?將數(shù)組元素復(fù)制到新數(shù)組
????????for?(int?j?=?0;?j?????????????Node?e;
????????????if?((e?=?oldTab[j])?!=?null)?{
????????????????oldTab[j]?=?null;
????????????????if?(e.next?==?null)
????????????????????newTab[e.hash?&?(newCap?-?1)]?=?e;
????????????????else?if?(e?instanceof?TreeNode)
????????????????????((TreeNode)e).split(this,?newTab,?j,?oldCap);
????????????????else?{?//?preserve?order
????????????????????Node?loHead?=?null,?loTail?=?null;
????????????????????Node?hiHead?=?null,?hiTail?=?null;
????????????????????Node?next;
????????????????????do?{
????????????????????????next?=?e.next;
????????????????????????if?((e.hash?&?oldCap)?==?0)?{
????????????????????????????if?(loTail?==?null)
????????????????????????????????loHead?=?e;
????????????????????????????else
????????????????????????????????loTail.next?=?e;
????????????????????????????loTail?=?e;
????????????????????????}
????????????????????????else?{
????????????????????????????if?(hiTail?==?null)
????????????????????????????????hiHead?=?e;
????????????????????????????else
????????????????????????????????hiTail.next?=?e;
????????????????????????????hiTail?=?e;
????????????????????????}
????????????????????}?while?((e?=?next)?!=?null);
????????????????????if?(loTail?!=?null)?{
????????????????????????loTail.next?=?null;
????????????????????????newTab[j]?=?loHead;
????????????????????}
????????????????????if?(hiTail?!=?null)?{
????????????????????????hiTail.next?=?null;
????????????????????????newTab[j?+?oldCap]?=?hiHead;
????????????????????}
????????????????}
????????????}
????????}
????}
????return?newTab;????//?新數(shù)組
}
默認(rèn)情況下,table.length = 16; 指定了 initialCapacity 的情況放到問(wèn)題 5 中分析
默認(rèn)情況下,threshold = 12; 指定了 initialCapacity 的情況放到問(wèn)題 5 中分析
默認(rèn)情況下,能存放 12 個(gè)元素,當(dāng)存放第 13 個(gè)元素后進(jìn)行擴(kuò)容
問(wèn)題 2 :table 的擴(kuò)容
/**
?*?Implements?Map.put?and?related?methods
?*
?*?@param?hash?hash?for?key
?*?@param?key?the?key
?*?@param?value?the?value?to?put
?*?@param?onlyIfAbsent?if?true,?don't?change?existing?value
?*?@param?evict?if?false,?the?table?is?in?creation?mode.
?*?@return?previous?value,?or?null?if?none
?*/
final?V?putVal(int?hash,?K?key,?V?value,?boolean?onlyIfAbsent,
???????????????boolean?evict)?{
????Node[]?tab;?Node ?p;?int?n,?i;
????if?((tab?=?table)?==?null?||?(n?=?tab.length)?==?0)
????????n?=?(tab?=?resize()).length;
????if?((p?=?tab[i?=?(n?-?1)?&?hash])?==?null)
????????tab[i]?=?newNode(hash,?key,?value,?null);
????else?{
????????Node?e;?K?k;
????????if?(p.hash?==?hash?&&
????????????((k?=?p.key)?==?key?||?(key?!=?null?&&?key.equals(k))))
????????????e?=?p;
????????else?if?(p?instanceof?TreeNode)
????????????e?=?((TreeNode)p).putTreeVal(this,?tab,?hash,?key,?value);
????????else?{
????????????for?(int?binCount?=?0;?;?++binCount)?{
????????????????if?((e?=?p.next)?==?null)?{
????????????????????p.next?=?newNode(hash,?key,?value,?null);
????????????????????if?(binCount?>=?TREEIFY_THRESHOLD?-?1)?//?-1?for?1st
????????????????????????treeifyBin(tab,?hash);
????????????????????break;
????????????????}
????????????????if?(e.hash?==?hash?&&
????????????????????((k?=?e.key)?==?key?||?(key?!=?null?&&?key.equals(k))))
????????????????????break;
????????????????p?=?e;
????????????}
????????}
????????if?(e?!=?null)?{?//?existing?mapping?for?key
????????????V?oldValue?=?e.value;
????????????if?(!onlyIfAbsent?||?oldValue?==?null)
????????????????e.value?=?value;
????????????afterNodeAccess(e);
????????????return?oldValue;
????????}
????}
????++modCount;
????if?(++size?>?threshold)?????????????//?當(dāng)size(已存放元素個(gè)數(shù))?>?thrshold(閥值),進(jìn)行擴(kuò)容
????????resize();
????afterNodeInsertion(evict);
????return?null;
}
/**
?*?Initializes?or?doubles?table?size.??If?null,?allocates?in
?*?accord?with?initial?capacity?target?held?in?field?threshold.
?*?Otherwise,?because?we?are?using?power-of-two?expansion,?the
?*?elements?from?each?bin?must?either?stay?at?same?index,?or?move
?*?with?a?power?of?two?offset?in?the?new?table.
?*
?*?@return?the?table
?*/
final?Node[]?resize()?{
????Node[]?oldTab?=?table;????????????????????//?此時(shí)的?table?!=?null,oldTab?指向舊的?table
????int?oldCap?=?(oldTab?==?null)???0?:?oldTab.length;?//?oldCap?=?table.length;?第一次擴(kuò)容時(shí)是?16
????int?oldThr?=?threshold;????????????????????????//?threshold=12,?oldThr?=?12;
????int?newCap,?newThr?=?0;
????if?(oldCap?>?0)?{????//?條件滿足,走此分支
????????if?(oldCap?>=?MAXIMUM_CAPACITY)?{
????????????threshold?=?Integer.MAX_VALUE;
????????????return?oldTab;
????????}
????????else?if?((newCap?=?oldCap?<1)?//?oldCap左移一位;?newCap?=?16?<1?=?32;
?????????????????oldCap?>=?DEFAULT_INITIAL_CAPACITY)
????????????newThr?=?oldThr?<1;?//?double?threshold????????????//?newThr?=?12?<1?=?24;
????}
????else?if?(oldThr?>?0)?//?initial?capacity?was?placed?in?threshold
????????newCap?=?oldThr;
????else?{???????????????//?zero?initial?threshold?signifies?using?defaults
????????newCap?=?DEFAULT_INITIAL_CAPACITY;????//?DEFAULT_INITIAL_CAPACITY?=?1?<4?=?16,?newCap?=?16;
????????newThr?=?(int)(DEFAULT_LOAD_FACTOR?*?DEFAULT_INITIAL_CAPACITY);
????}
????if?(newThr?==?0)?{????//?條件不滿足
????????float?ft?=?(float)newCap?*?loadFactor;
????????newThr?=?(newCap?float)MAXIMUM_CAPACITY??
??????????????????(int)ft?:?Integer.MAX_VALUE);
????}
????threshold?=?newThr;????????//?threshold?=?newThr?=?24;?重置閥值為?24
????@SuppressWarnings({"rawtypes","unchecked"})
????????Node[]?newTab?=?(Node [])new?Node[newCap];?????//?初始化?newTab,?length?=?32;
????table?=?newTab;????????????//?table?指向?newTab,?length?=?32;
????if?(oldTab?!=?null)?{????//?擴(kuò)容后,將?oldTab(舊table)?中的元素移到?newTab(新table)中
????????for?(int?j?=?0;?j?????????????Node?e;
????????????if?((e?=?oldTab[j])?!=?null)?{
????????????????oldTab[j]?=?null;
????????????????if?(e.next?==?null)
????????????????????newTab[e.hash?&?(newCap?-?1)]?=?e;????????//?
????????????????else?if?(e?instanceof?TreeNode)
????????????????????((TreeNode)e).split(this,?newTab,?j,?oldCap);
????????????????else?{?//?preserve?order
????????????????????Node?loHead?=?null,?loTail?=?null;
????????????????????Node?hiHead?=?null,?hiTail?=?null;
????????????????????Node?next;
????????????????????do?{
????????????????????????next?=?e.next;
????????????????????????if?((e.hash?&?oldCap)?==?0)?{
????????????????????????????if?(loTail?==?null)
????????????????????????????????loHead?=?e;
????????????????????????????else
????????????????????????????????loTail.next?=?e;
????????????????????????????loTail?=?e;
????????????????????????}
????????????????????????else?{
????????????????????????????if?(hiTail?==?null)
????????????????????????????????hiHead?=?e;
????????????????????????????else
????????????????????????????????hiTail.next?=?e;
????????????????????????????hiTail?=?e;
????????????????????????}
????????????????????}?while?((e?=?next)?!=?null);
????????????????????if?(loTail?!=?null)?{
????????????????????????loTail.next?=?null;
????????????????????????newTab[j]?=?loHead;
????????????????????}
????????????????????if?(hiTail?!=?null)?{
????????????????????????hiTail.next?=?null;
????????????????????????newTab[j?+?oldCap]?=?hiHead;
????????????????????}
????????????????}
????????????}
????????}
????}
????return?newTab;
}
當(dāng) size > threshold 的時(shí)候進(jìn)行擴(kuò)容
擴(kuò)容之后的 table.length = 舊 table.length * 2,
擴(kuò)容之后的 threshold = 舊 threshold * 2
問(wèn)題 3、4 :2 的 n 次冪
static?final?int?hash(Object?key)?{
????int?h;
????return?(key?==?null)???0?:?(h?=?key.hashCode())?^?(h?>>>?16); //?這里的處理,有興趣的可以琢磨下;能夠減少碰撞
}
//?put
table[h?%?table.length]?=?value;
//?get
e?=?table[h?%?table.length];

1&1=1;
0&1=0;
1&0=0;
0&0=0;
1010&1111=1010;??????=>?10&15=10;
1011&1111=1011;??????=>?11&15=11;
01010&10000=00000;???=>?10&16=0;
01011&10000=00000;???=>?11&16=0;
h%length 效率不如位運(yùn)算快
h&length 會(huì)提高碰撞幾率,導(dǎo)致 table 的空間得不到更充分的利用、降低 table 的操作效率
問(wèn)題 5:指定 initialCapacity

/**
?*?Returns?a?power?of?two?size?for?the?given?target?capacity.
?*?返回?>=?cap?最小的?2^n
?*?cap?=?10,?則返回?2^4?=?16;
?*?cap?=?5,?則返回?2^3?=?8;
?*/
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;
}
問(wèn)題6:加載因子
如果loadFactor太小,那么map中的table需要不斷的擴(kuò)容,擴(kuò)容是個(gè)耗時(shí)的過(guò)程
如果loadFactor太大,那么map中table放滿了也不不會(huì)擴(kuò)容,導(dǎo)致沖突越來(lái)越多,解決沖突而起的鏈表越來(lái)越長(zhǎng),效率越來(lái)越低
而 0.75 這是一個(gè)折中的值,是一個(gè)比較理想的值
總結(jié)

推薦閱讀:
【80期】說(shuō)出Java創(chuàng)建線程的三種方式及對(duì)比
【79期】別找了,回答Spring中Bean的生命周期,這里幫你總結(jié)好了!
【78期】別找了,Java集合面試問(wèn)題這里幫你總結(jié)好了!
微信掃描二維碼,關(guān)注我的公眾號(hào)
朕已閱?

