2 b- P- j/ I" d3 d v3 w- P/ `源码分析重要属性 ) a4 Z6 e" a, a, B8 \/ E//默认初始容量是16" c5 i/ W3 i% M, h; I1 B
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 : B; O- R8 Q4 X) }( W2 W & H1 a( k! Q# C, Y4 [* E& L //最大容量是2的30次方 }& W& B1 T& C% K% y, K! b
static final int MAXIMUM_CAPACITY = 1 << 30; ( f/ S+ {% ?1 B- E% l7 f8 z 2 ^8 V$ P2 [& J- Z k$ d, ` //当构造方法中没有指定负载因子时用这个默认的! }+ ^$ n% X# @* C5 [
static final float DEFAULT_LOAD_FACTOR = 0.75f; 0 s+ w+ V2 F- T* c7 \5 _ d% _3 z e" H! E) R% d6 k# `/ a6 B //当链表中桶的个数大于等于8就会变成红黑树 ( x7 }5 L2 ]! P/ J static final int TREEIFY_THRESHOLD = 8; + S7 W' J' L! s! h' E; ^ / S; z$ [& l. g //当红黑树大小小于等于6时红黑树会转化成链表 % l# T( [1 n g8 G, ]$ J static final int UNTREEIFY_THRESHOLD = 6; & k7 ~* T: f# A5 c x. \ ) v" _- f7 Q0 f3 C, m //当数组容量大于64时链表才能转成红黑树 ( S+ G$ O: K1 q4 f static final int MIN_TREEIFY_CAPACITY = 64;5 o+ k/ a5 x: o6 z
4 ?8 Z* {9 l: ?2 O$ D* r' o: K //数组,数组的大小是2的n次幂4 @, J& Q& A7 P
transient Node<K,V>[] table; - ~, o6 d2 y. C) @" M2 \ //存放具体集合( q! c% m/ @9 v( S4 [6 h. K
transient Set<Map.Entry<K,V>> entrySet; " t2 {, O9 l* Q" R0 y& w6 ]! P0 W 6 {% U& O1 q0 G //存放元素的个数, f$ O6 ]. ^/ z0 f* G" _
transient int size; 6 v! V7 }6 T3 V. B / ?' n' W" I! |/ u& A0 v //每次更改结构的计数器 : \+ f6 A( c1 J) O5 H2 a' ` transient int modCount; % ~) ^' L* h% ? # e0 d# Y; E1 k. F- E% C //当HashMap所能容纳键值对数量的最大值,超过这个值,需要扩容' O; g/ \ h- {; W, D- `
int threshold; " a) t9 C! ^/ }) K0 P: d7 N* T. s) J! X k
//负载因子1 H5 X9 X0 U- i7 E" U7 N/ K
final float loadFactor;2 \# C0 ^5 L" K* C: a
loadFactory加载因子' a9 B/ |$ V7 x, J& q
loadFactory加载因子是通知数组存放数据的疏密程度,他的值越接近于1,存放在数组到的数据也就越密集,也就是说这个值越大,链表的长度会增加的越快。当他的值趋近于0,存放在entry中的数据就会越少,也就越稀疏。 u# {5 {; H$ u, y8 t k; h1 g* _
/ N% a4 W+ @2 F# U( f- J! l- _- W. I8 t
threshold; l2 _+ F5 j3 E( g) R
给定的默认容量大小是16,负载因子时0.75,Map在使用过程中不断的往里面存放数据,当存放的桶的个数达到了12=16*0.75,就会扩容,扩容的时候比较消耗性能。# y+ _% O# r1 W+ Q7 p# t2 g7 G
8 B" X1 m8 N( b2 I& |& A$ q你也许有疑问,12是怎算出来的,其实这个就是threshold属性,threshold=capacity*loadFactoy,当Size大于等于threshold这个值,就需要对数组进行扩容操作了。/ u. ~8 v3 X& T1 D# y8 {# x$ H
2 ~. [* d H) i/ @
从上面的源码我们可以知道,容量最大是2的30次方,当数组大小 大于等于64并且链表长度大于等于8时,链表就会转化成红黑树。当红黑树的桶的个数 小于等于6时就会变回链表。 * j E5 S0 ]5 U- n* F4 d' ]% O8 s @% [( R8 G3 {1 h* F
链表Node节点( p- F* j6 B. ]2 M# A% f
* S' ~- `2 M) R$ Z//Node 节点实现了Map.Entry<K,V> 5 t: N$ c% }6 B7 U0 Hstatic class Node<K,V> implements Map.Entry<K,V> {+ C$ K" W* [ q1 a
final int hash; //hashCod6 G- V! ~) y, w; a( j- _) K
final K key;//键 * l4 O* J& }, `. b/ ?1 R V value;//值 # H! s' q" `6 c9 S( I8 N% E" z" `+ j Node<K,V> next;//指向下一个节点 & G6 Y2 B! N0 E, Q: ]8 N& L% h1 K, r //构造函数; x) e3 a* M$ [1 i! ^: \
Node(int hash, K key, V value, Node<K,V> next) {4 o- u: i* j: n
this.hash = hash; # |5 L; y. R: |4 G% Q/ V this.key = key;6 i0 |" N: h$ p9 L
this.value = value;3 Y/ e0 o& a# I" \4 t
this.next = next;8 o4 G! D, w( _/ `
} 0 K6 A* I& ?. H! w# V $ Z3 n: p: T Q: R& N0 [ public final K getKey() { return key; }/ ]* j9 D& p0 U& ?# { u
public final V getValue() { return value; }; E0 P, y0 f2 N& {' u
//重写toString方法 3 v* d' P# ?9 [! E; n% R public final String toString() { return key + "=" + value; }" N8 h' Q0 p8 @* H9 m" i; v/ h) l
//重写hashCode方法0 y; |' e7 J8 s; l) ?
public final int hashCode() { * K e. e7 M7 S return Objects.hashCode(key) ^ Objects.hashCode(value); ) I Q v% j a8 z. z- G } z1 n1 D) P/ ^1 b ! H$ r4 h6 [4 {/ S5 `( w public final V setValue(V newValue) { + W4 o, t7 V+ C+ K' ^& G V oldValue = value; # g# K" V- C9 |' P: u! M8 W value = newValue; 9 X/ E% L, L. S8 V return oldValue;, B0 X, n' I' k3 n; H7 V- c
}8 V- m3 K7 s) L$ y/ h0 e- Y
//重写equals方法 " S/ Y, q+ V* J+ v- P2 { public final boolean equals(Object o) { - f# O" \. Q: f$ h; g; o& } //如果内存地址一致直接返回true ) F, s6 z/ E9 J- h if (o == this) - v6 x* r1 V9 ]( H. Z return true;/ E+ p n9 B+ f6 Y1 ^
//比较的节点必须实现这个Map.Entry h# W) [9 A+ A$ y1 k' x. R+ A, T
if (o instanceof Map.Entry) {7 @ W; `9 f8 o# W* [
Map.Entry<?,?> e = (Map.Entry<?,?>)o;, W9 S5 W. Z# D0 s
if (Objects.equals(key, e.getKey()) && ; c8 o- v1 D/ A! P Objects.equals(value, e.getValue()))9 Q9 y7 o. u* U4 b$ n& c
//键和值都相等才能返回true5 D# v* F& b8 C2 z* U- h# ]
return true;9 L5 z$ m- ^+ i# V. n/ }
}- I: A( e9 U& z- o- S y& D
return false;& K; k# A5 e8 | t/ T2 U- t% ^
}* u5 i3 ?; O- m6 p; M$ |
}/ g9 W4 D- d5 W5 q
$ `" Q k! Y6 k. v' e9 f* r" k7 p
& v+ m5 u" e! ?' ^( @! `+ \3 Q红黑树节点结构) i( Z ]* J3 R: j5 o# ]4 }
//TreeNode继承了LinkedHashMap中的Entry节点) z* ^3 f. P1 s
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {% D: h% x' b7 E& ^: `0 j
TreeNode<K,V> parent; // 红黑树的父亲节点 * X/ F8 O: g( a4 s' P' c6 @ TreeNode<K,V> left; //左子树 ) }0 k# O! Y- P3 S0 f' v+ E6 J TreeNode<K,V> right;//右子树+ j8 P- Z: L) ?
TreeNode<K,V> prev; // 链表中的节点,在删除元素的时候可以快速找到他的前驱节点- v I; t: ]+ i8 B; i
boolean red; //是否变色,0 M) f! y9 @7 T% L# G5 ?; k$ I
//构造方法8 |8 {" X: B' N' s
TreeNode(int hash, K key, V val, Node<K,V> next) {0 Q* @( `1 [' ]" z1 m
super(hash, key, val, next); & G1 H8 ?1 f! f# O* V/ L# @) a } 2 C0 ?# v/ M2 @ ( K# Q V% ^' e) Y /** 0 R' W$ u% m' v2 C" J * 返回根节点 1 N( q: ~, ~( `" I* F% G */ 4 v! P+ u- d! x K p: @7 e final TreeNode<K,V> root() {; e8 P3 H3 t- [6 C0 m6 U8 S
for (TreeNode<K,V> r = this, p;;) { ) t0 t' f' O% V6 N; G if ((p = r.parent) == null) 1 q7 N+ W' Z3 r) f/ y5 ?6 h return r; 9 P3 w) b- S/ J8 m2 R r = p;& d; M4 l/ }. T; U- S, T
}0 f+ Q# J/ T7 P3 p6 b; b( p$ ^
} & Y; g2 H- _/ s ^3 n5 o. ^ |9 c# w- T构造方法/** ! X& k# D$ ]9 P" ^5 [- O+ N7 o* 构造一个空的HashMap并指定初始容量和负载因子。 ( r) u& o" }# f1 N! n* ) N+ ?* }: M1 s# L f**/ # m) [" C1 }- ]; Spublic HashMap(int initialCapacity, float loadFactor) {" X/ c$ K- ~* _6 h' x3 G* n# x% U' ~; m
//如果初始容量小于0,抛出非法参数异常, T2 c- U" ~6 k0 u* z8 I
if (initialCapacity < 0) 3 J* r G; ~- f% L, [ throw new IllegalArgumentException("Illegal initial capacity: " +8 g" N; M) q% o' c/ q7 R- d3 C
initialCapacity); 1 W3 |6 Y1 T- a4 X! B //如果初始容量大于最大的容量也就是2^30,那么就按照最大的初始容量赋值。 & S! \" ], N2 {6 J& ^ if (initialCapacity > MAXIMUM_CAPACITY)+ a( P$ A) l$ l; s
initialCapacity = MAXIMUM_CAPACITY; e1 W5 S1 C& {( j( F
//如果负载因子小于0或者是NaN(float NaN = 0.0f / 0.0f;)也会抛出非法参数异常 ( `% C/ K( ~2 L) d0 }9 g6 b if (loadFactor <= 0 || Float.isNaN(loadFactor))( b6 |* H9 Z2 D9 q7 ~+ l! V1 g
throw new IllegalArgumentException("Illegal load factor: " +8 |7 H5 a# W6 [: X! P! T# r( P9 |9 Z+ S
loadFactor); / k( C) B, }6 _& g5 e this.loadFactor = loadFactor; 2 T* ?2 {6 m( x) o! J1 ?! L$ F4 f this.threshold = tableSizeFor(initialCapacity); + S, m+ ?! u5 m, G& I- B* \4 A } 0 F# o" i; n9 z$ B$ c, r//如果只是指定了初始容量那么负载因子就是默认的0.75) k* n& z/ [: B u
public HashMap(int initialCapacity) { 7 C& }% R4 W6 C2 L2 s' h% a' P this(initialCapacity, DEFAULT_LOAD_FACTOR);3 P: y, ~* o1 c4 w
} ` n, S1 O8 T; w; V
& k/ J$ s- o9 A m$ o /**3 w! @: a: g3 Z, q1 y- v
* 如果什么都没指定,也就是无参构造,则初始容量是16和负载因子是0.75( y A4 `) b8 w! Q6 w) C. Y
*/ : }" {1 K: d5 N; z4 _; W public HashMap() { - t: R* t* r% w; K0 I this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted7 G" [$ g5 U2 z! k
} m# s* M: S) }, n
: m6 j% Y3 i- x3 T- P /** 1 K) t- o h- h7 S * 包含另一个Map的映射,如果被映射的Map是一个null会抛出空指针异常, w K! P& j b
* 负载因子时默认的 L, i* E* k' t! Z w- m
*/# G0 _0 f* q: I. U
public HashMap(Map<? extends K, ? extends V> m) {$ j+ q. \" M8 x" f, E
this.loadFactor = DEFAULT_LOAD_FACTOR; 0 d2 J# D P& m) ^6 V, E putMapEntries(m, false);7 c3 i4 E5 [) R
} * f# b( ^- z( F: q8 a& Y+ I7 ^' }8 i8 T; A
final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) { $ _) ~2 ^" S O int s = m.size();//s是map的大小2 a* h7 v7 j! Z5 V+ j, u. o- I
if (s > 0) { T1 T% }7 ?3 ~& h! ]6 j
if (table == null) { // pre-size - H8 o2 V# {$ G0 Z. j; V2 v float ft = ((float)s / loadFactor) + 1.0F;7 c( R/ \5 h+ t- G& _) e2 N8 `
int t = ((ft < (float)MAXIMUM_CAPACITY) ?* z" C4 R6 u: J4 d3 o
(int)ft : MAXIMUM_CAPACITY); 0 z; |' |& V1 j, V. V" ? if (t > threshold)//如果t大于扩容的阀值就初始化阀值 5 R, P. D7 ]4 l7 J1 y7 Z threshold = tableSizeFor(t); - [3 c a* @8 g4 T# x% _4 P" E- t } ) d9 x5 C3 n3 R; u: }0 F) N3 e //如果这个map中的元素个数大于扩容的阀值就得扩容* }0 H9 } m* \6 X* I3 R9 Q* V5 M
else if (s > threshold)' R* Y9 O7 B1 x- V. z7 A. ?& X6 n
resize();* R2 B# \% L6 y Q X: g" {. H
//将map中的key和value都添加到HashMap中3 I$ B( r6 g5 @% J( X
for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) { 1 L. k2 J2 F2 M( L: V s" @1 o0 y. d K key = e.getKey();% E- |, \6 X* f4 q) F
V value = e.getValue();3 a7 u& i3 ^' Q+ }
putVal(hash(key), key, value, false, evict); 3 V3 m1 D, Y$ {1 j; K* n: h; x } 9 d& ^* g3 f/ }! {) n }/ H; ^- F' b; k6 a$ U8 ~. B
}& Q4 y+ O( L/ U: }
; u9 G: H+ `; j& q0 U9 |; w
' U5 x* Z: R! O8 t/ i* k/**/ D3 q. q$ a' J" v
* 构造一个空的HashMap并指定初始容量和负载因子。- o; T! c# {; |0 P0 G, `
* / q' D/ X$ ~5 E; P! K* a6 }**/ . S% |. g+ S, \3 b2 ?public HashMap(int initialCapacity, float loadFactor) { * X; d2 ], W( v4 v# M& k6 |. u //如果初始容量小于0,抛出非法参数异常& Y2 F; w9 f' v& F7 I& X( k: U
if (initialCapacity < 0)# y( Z3 u0 L+ y2 l
throw new IllegalArgumentException("Illegal initial capacity: " + : ?+ b$ l5 U$ _5 W) F% S6 k! V initialCapacity);; z( Y$ F( F! p! c
//如果初始容量大于最大的容量也就是2^30,那么就按照最大的初始容量赋值。! b& i+ J4 ~2 E9 C$ \3 c% E
if (initialCapacity > MAXIMUM_CAPACITY) . s& b/ d3 `6 |4 I/ D: T initialCapacity = MAXIMUM_CAPACITY;7 O& R( s5 b* u! f
//如果负载因子小于0或者是NaN(float NaN = 0.0f / 0.0f;)也会抛出非法参数异常 D# R) ?7 v5 _2 R' u" Y if (loadFactor <= 0 || Float.isNaN(loadFactor)) 6 d0 o/ x- y5 e9 } throw new IllegalArgumentException("Illegal load factor: " +* G. R% x! h& L
loadFactor);/ I# x& a: m/ U0 K
this.loadFactor = loadFactor;" d* D) p- P9 T
this.threshold = tableSizeFor(initialCapacity);+ k0 o. @. H7 ]% F
}9 e6 t/ z% @2 \0 S/ ]; U( Q
//如果只是指定了初始容量那么负载因子就是默认的0.75 # o- d- ^' N( A. M9 r$ cpublic HashMap(int initialCapacity) { & w$ G$ h3 B0 e* H this(initialCapacity, DEFAULT_LOAD_FACTOR);) t' w& H# ]- m! P( ]; N
} 0 a8 }, v8 A; r& _: o1 {$ i7 {. O$ u) n* l w
/**# I: m% w u7 F1 J, J
* 如果什么都没指定,也就是无参构造,则初始容量是16和负载因子是0.75 D. W* c# @0 F' Y */ + g( Y# m+ ?; {( u. S) c# o7 b. K4 V, j public HashMap() { 9 W6 J/ O6 V" t! k- c this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted/ v- P. y- g1 Q$ C
} n- b2 O3 ~6 m
4 r, C- ~- y. Y" ?/ e
/**8 M- O, x d2 ]" l
* 包含另一个Map的映射,如果被映射的Map是一个null会抛出空指针异常: ?& N0 M, s4 C/ L* ]- t
* 负载因子时默认的 $ b# c9 q" [1 N# g6 ?! S; |8 W */ 4 X2 ?+ q5 w# O, b public HashMap(Map<? extends K, ? extends V> m) { 4 A$ U" U z& Z% o this.loadFactor = DEFAULT_LOAD_FACTOR; , `0 m6 F$ j. `9 x1 l putMapEntries(m, false); 8 ]) B1 F7 x: _, e8 n, S s9 b }& F; |2 N, `* n! L2 @
! `+ d. R% H* K* J+ {( t7 u
final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) { ; R* @1 ?* y! S5 N J int s = m.size();//s是map的大小 7 Z- N M$ r3 q6 u V if (s > 0) {' m2 g" E5 G: n- F: X8 X0 \
if (table == null) { // pre-size / G& P# C* A) N* N float ft = ((float)s / loadFactor) + 1.0F; * f& G! Y5 x6 h. | l int t = ((ft < (float)MAXIMUM_CAPACITY) ?! e, h0 j u7 a6 L3 z9 T
(int)ft : MAXIMUM_CAPACITY);$ z" M) O6 S8 K$ Z& I
if (t > threshold)//如果t大于扩容的阀值就初始化阀值 : x* s0 u' v) Q+ C ?8 | threshold = tableSizeFor(t);: g5 o6 H% D- @, `% M+ t5 A# Z
} w2 j" y8 C* P: c) v, p
//如果这个map中的元素个数大于扩容的阀值就得扩容 9 L' a1 f; L3 g# J0 d else if (s > threshold) o8 A# x. q: c3 \; h$ }' _ resize();4 r' [$ S- q* h6 T) v
//将map中的key和value都添加到HashMap中 6 x& X! M5 \7 y9 e for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {! b7 [2 _8 H, W+ E6 l1 F
K key = e.getKey();, k3 @, N: Y2 V% o4 V7 _
V value = e.getValue();: m- c- K o% N( d* K$ p4 h
putVal(hash(key), key, value, false, evict); 9 q+ [/ m& F1 u( W& @+ B) r }9 m- W3 L E' M9 j( }+ _/ v
} 3 z; z" c5 H9 r- N } ! B% Q& K' ~ S9 X W# o# p7 j& Z9 Y( o3 k put方法
向HashMap中添加元素
% ^0 Y+ p m% q' g
6 S2 ?# X- k4 B6 w public V put(K key, V value) { 2 H- _+ Y0 F, G6 o9 U3 y8 R: t return putVal(hash(key), key, value, false, true);$ P w; k Y9 k
}5 r1 A" q; B* n8 r H( v
7 J1 D0 W5 Y: E% I
//扰动函数(哈希函数) # Z- u$ I n; w static final int hash(Object key) { # P- _! m& V/ P; ~% }+ R int h; 3 {& P! z: r% H9 U" l //如果key是null,那么映射出来下标是0,否则将key的hashCode和h无符号右移16位做疑惑操作,使计算出的hash更加分散。0 o5 T; V6 B0 b: E H5 w" [- R2 X
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); . T8 N% f) n9 d4 E2 }# i' t }: w4 N" J3 q/ w3 H" y
6 Z4 h" i: `4 V/ f8 n+ |, P# B//onlyifAbsent默认是false,表示即使key存在也可以覆盖旧值。 ' ?( c2 D! ~# G k2 M0 I" ? final V putVal(int hash, K key, V value, boolean onlyIfAbsent, 6 J7 q9 C8 O& A( ^3 f5 E boolean evict) { $ N" x3 v5 Z- L) q c9 X //n表示数组的长度,i表示数组的下标,p表示下标 i对应的Node 3 G- H# ~! ^* ], X! C' C9 c Node<K,V>[] tab; Node<K,V> p; int n, i; 7 D% N. s# J0 ]$ s if ((tab = table) == null || (n = tab.length) == 0)//如果数组为空需要进行扩容- N4 l4 E% s% x
n = (tab = resize()).length; # X: J* Z3 V( [ if ((p = tab[i = (n - 1) & hash]) == null)//如果当前位置上没有节点那就新生成一个节点放上去3 X0 u6 | W! w/ M! U9 P
tab = newNode(hash, key, value, null);1 S- Z% a6 t6 ~4 ?% h, S- H0 e
else {//否则就代表这个位置已经有节点占用了, 1 d) ^6 f( j) z) l4 u8 w8 t9 \ Node<K,V> e; K k;//e表示临时节点! C8 v8 d6 j2 O
if (p.hash == hash && 5 {1 U1 v+ Y/ g: O2 y; V. `' E; z ((k = p.key) == key || (key != null && key.equals(k)))) t) N/ M! }$ S+ m' l! X: B+ M
// 如果key的hash和key本身的值都相等,直接把当前新增家电赋值给临时变量 e/ m+ r- D: h& p, ^( R% |7 @+ Y+ B: M
e = p; , o1 a$ ]. B. C, E" \* t: X0 G2 x //这里开始判断使用哪种类型的数据结构开始添加节点,如果是红黑树,就用红黑树的新增方式 $ k5 w0 a6 w$ `7 n. M0 t else if (p instanceof TreeNode) : ^) Q9 b, M4 n e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);( ^& r0 Y7 H& e0 @& ]5 A& V
else { % R3 m* \4 q a% J4 s7 e! n* } //否则采用链表的方式新增节点,遍历到链表的末尾,追加到后面" Y9 L u2 p6 b7 F* U; J
for (int binCount = 0; ; ++binCount) {/ ?7 u d3 Y# \- f7 h" Z6 g. N
//p.next==null表示到链表尾部 2 m+ ^$ v2 ^5 u( h if ((e = p.next) == null) { 4 X( X0 ? G$ e" s //把新建的节点放在链表的最后1 q: s6 b' Y9 S
p.next = newNode(hash, key, value, null); 5 n: z1 f* O' l //节点个数大于等于树化的阀值就需要转换成红黑树. ^& Z0 H& S' l& m2 J, o& u8 f2 Z" j; e
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st5 D# a3 q# N7 N: u& n6 [
treeifyBin(tab, hash); a# S7 {2 b6 j5 d( C- a
break;//跳出循环; B; N' L( U: @& F) \' F; B! w- w
}1 \& N( v5 N e5 d1 i
//循环遍历中发现 有元素和新增节点相等就结束循环; ]6 A, h( J9 U7 n7 G. t; t Z* Q
if (e.hash == hash && : P+ C8 e( U! ` ] ((k = e.key) == key || (key != null && key.equals(k)))) , c; q6 X# y* u- b1 k0 L1 r break;//相等就跳出循环8 l; @# W6 F5 a
p = e;! U$ J t2 a0 A5 N* X) N% ^9 N# [5 X
} / |; Q+ C# ?" N. z/ S" }# \+ J } 4 U4 X) m5 U) s/ P! O$ j //说明新节点的新增位置已经找到了 * J5 d8 i6 O/ `( x if (e != null) { // existing mapping for key: v0 V; M, Y9 s0 |. F3 l6 o" d
V oldValue = e.value;( E$ v6 O* W1 M* Y
//当onlyIfAbsent=false时才会覆盖 , m( h; o# Y5 i! Y+ O5 F# A if (!onlyIfAbsent || oldValue == null) # c) z2 k- r6 `* X; w8 R e.value = value; " `' G6 w2 K& s; ` afterNodeAccess(e); m7 \1 ?6 B! J4 `7 i3 U
//返回旧的值" O7 S4 h! `" }. S& f4 C9 P
return oldValue; & S$ q; e+ p' y: Q }; [% \" U( _; }! N* F) j
} " e$ o2 ?! v2 L0 g //结构修改计数器加一 % |8 r! H8 A. l8 c0 ?! |6 W5 I% }& a ++modCount; 3 [; B9 g9 S0 X) m" h: _ //如果实际大小 大于扩容的阀值就会再次扩容' J2 O& s; f& }, I0 A% A
if (++size > threshold) # \7 V0 u: V5 a resize();' n6 Y( p D" j! @ }) t0 D) b4 s
//插入后回调,具体实现交给了LinkedHashMap& d B* E7 Z5 q% h+ `$ {4 v
afterNodeInsertion(evict);; w3 }9 A- p1 q$ E' [
return null; {' C- `+ [4 M6 F- w$ J K: d
}3 Q& y9 \( g% y) L 红黑树新增节点的过程: l9 p T7 o4 F/ ?1 B
$ h p7 x$ z$ `$ H' a1 j
final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab,% A" M' s1 Q1 X* i$ G1 Y
int h, K k, V v) { # V% q( P) s, m8 T& x/ F Class<?> kc = null;) T) u( u9 g5 l; N0 I
boolean searched = false; " v* \& \* @( I, p2 W. M8 W //找到根节点! y$ [: Y! S ?% S9 ^) u6 E
TreeNode<K,V> root = (parent != null) ? root() : this;3 U' @/ Z. Z1 E. V. }# w9 ]: I
for (TreeNode<K,V> p = root;;) { / w1 O7 z; W. _% I3 X/ H int dir, ph; K pk; * S3 _8 I" \9 c6 y //如果p的hash大于 h,那p就在h的右边 5 p- n: k2 @, n- t* B& K if ((ph = p.hash) > h)7 h% {/ t; |. K$ |
dir = -1;: k+ N9 D! S3 _8 w! n, Z" f8 j8 G
//如果p的hash小于 h,那p就在h的左边( G" E M) N! n' m# }8 V$ z& G
else if (ph < h) $ r1 Y+ F% {$ p& t! E dir = 1;7 {$ Z6 S, T" v" U; u9 T* G2 ?
//如果将要新增的key已经在树中存在了那就直接返回p,这里代表插入的key没有实现Comparable接口,那就通过equals方法和值 比较是不是同一个key0 @6 Z$ v. J/ Q1 j" T
else if ((pk = p.key) == k || (k != null && k.equals(pk))) ; a% ^2 |- P6 {' v& @! \ return p;# e7 U ]& {( I
//如果key实现了Comparable的话,不再用hashcode比较,需要用compareTo方法0 u2 ]% h, U2 M6 c ^
else if ((kc == null &&# G! L2 i; ?! t* P
//如果key没有实现Comparable接口,那么 comparableClassFor(k)返回的就是null/ N3 B! E! ]; |# Y0 }% `5 Q
(kc = comparableClassFor(k)) == null) ||( j# j0 n6 ^% T. H# N6 A) }
//当前节点的键和入参的键不相等- F' F) i( a; I9 E2 ~
(dir = compareComparables(kc, k, pk)) == 0) { : F6 M$ a o8 j if (!searched) { " u/ U# a2 d6 N# I0 Q TreeNode<K,V> q, ch;9 a$ K1 o3 P' q. |
searched = true; 2 c' B+ i% B# ~ if (((ch = p.left) != null &&( K. h* y S- d
(q = ch.find(h, k, kc)) != null) ||8 B6 N* J# @% P0 D! o4 [6 e
((ch = p.right) != null &&3 S1 m. r# Y+ R# J: Y
(q = ch.find(h, k, kc)) != null))( A. M1 s+ a) e! E1 [$ @/ F
return q;# x2 V) A- |- E( z) X. O+ e. i
} * X% T4 F2 o$ |# g7 j8 Q; X) ` dir = tieBreakOrder(k, pk);- J" Z' T; f; x
} # i7 v3 I/ j# `; ^8 i& R# q+ h% f- p; R! m2 [$ J- Y' a* c
TreeNode<K,V> xp = p;6 @( I6 j* f4 L$ a8 A4 b" `5 a
if ((p = (dir <= 0) ? p.left : p.right) == null) {' |4 V- P: D' E! r. g/ V
Node<K,V> xpn = xp.next;0 `/ J. s" e, `( d C6 a
//生成新节点 # |2 D% b6 X; }( a [ TreeNode<K,V> x = map.newTreeNode(h, k, v, xpn);$ d2 z5 t) p/ r/ W! c
if (dir <= 0) " J$ d% {8 E$ g* }- e( ~ //如果dir=-1 新节点放在左子树 7 R& J: g1 ~0 ~ xp.left = x;0 I6 W5 j. M, ~( z6 s
else1 b( T8 V: T5 {8 _. @" ]
//如果dir=1 新节点放在右子树5 Z3 B1 i* x% @
xp.right = x;6 A/ n% }, y3 `. p1 l
//当前节点和新节点建立父子关系后前后关系 F( N) { A4 W! S8 {. f- `- |' h# d5 w xp.next = x;( I1 N. ^$ J" b+ g( S! i5 T# G q3 d
x.parent = x.prev = xp;1 G( z* t r! [+ Z' j3 D
if (xpn != null); Y6 o. V5 H* ]! |1 b- ^: [6 |
((TreeNode<K,V>)xpn).prev = x; # X; O8 w! R# H# c: W; M moveRootToFront(tab, balanceInsertion(root, x)); 7 Q( f( S' z$ n6 B* b //balanceInsertion 对红黑树进行着色或旋转,以达到更多的查找效率,着色或旋转的几种场景如下 . ?, z- ]/ j8 u' O: r //着色:新节点总是为红色;如果新节点的父亲是黑色,则不需要重新着色;如果父亲是红色,那么必须 通过重新着色或者旋转的方法,再次达到红黑树的5个约束条件/ u8 z" F, I0 M; ^9 {+ T
//旋转: 父亲是红色,叔叔是黑色时,进行旋转! ^1 w- ]4 _6 o4 E9 O! \/ f- i" Q
//如果当前节点是父亲的右节点,则进行左旋 + @: N- @& h$ r* v, _1 ` //如果当前节点是父亲的左节点,则进行右旋4 m, }' N( l! [, u3 b1 x- h