/*------------------------------------------------------------ */
// Cloning and serialization
@SuppressWarnings("unchecked")
@Override
public Object clone() {//返回一个HashMap实例的浅拷贝:关键字和值本身并没有拷贝
HashMap
try {
result = (HashMap
} catch (CloneNotSupportedException e) {
// thisshouldn't happen, since we are Cloneable
thrownew InternalError(e);
}
result.reinitialize();
result.putMapEntries(this, false);
returnresult;
}
//当序列化HashSet时,也会使用这些方法
finalfloat loadFactor() { returnloadFactor; }
finalint capacity() {
return (table != null) ? table.length :
(threshold > 0) ? threshold :
DEFAULT_INITIAL_CAPACITY;
}
privatevoidwriteObject(java.io.ObjectOutputStream s)
throws IOException {//将HashMap实例的状态保存到流中(比如,序列化它)
intbuckets = capacity();
// Write outthe threshold, loadfactor, and any hidden stuff
s.defaultWriteObject();
s.writeInt(buckets);
s.writeInt(size);
internalWriteEntries(s);
}
privatevoidreadObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException {//从流中重建HashMap实例,比如反序列化
// Read in thethreshold (ignored), loadfactor, and any hidden stuff
s.defaultReadObject();
reinitialize();
if (loadFactor <= 0 || Float.isNaN(loadFactor))
thrownew InvalidObjectException("Illegal load factor: " +
loadFactor);
s.readInt(); // Read and ignore number of buckets
intmappings = s.readInt(); // Read number of mappings (size)
if (mappings < 0)
thrownewInvalidObjectException("Illegal mappings count: " +
mappings);
elseif (mappings > 0) { // (if zero, use defaults)
// Size thetable using given load factor only if within
// range of0.25...4.0
floatlf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
floatfc = (float)mappings / lf + 1.0f;
intcap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
DEFAULT_INITIAL_CAPACITY :
(fc >= MAXIMUM_CAPACITY) ?
MAXIMUM_CAPACITY :
tableSizeFor((int)fc));
floatft = (float)cap * lf;
threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
(int)ft : Integer.MAX_VALUE);
@SuppressWarnings({"rawtypes","unchecked"})
Node
table = tab;
// Read thekeys and values, and put the mappings in the HashMap
for (inti = 0; i < mappings; i++) {
@SuppressWarnings("unchecked")
K key = (K) s.readObject();
@SuppressWarnings("unchecked")
V value = (V) s.readObject();
putVal(hash(key), key, value, false, false);
}
}
}
/*------------------------------------------------------------ */
// iterators
abstractclass HashIterator {
Node
Node
intexpectedModCount; // for fast-fail
intindex; // current slot
HashIterator() {
expectedModCount = modCount;
Node
current = next = null;
index = 0;
if (t != null && size > 0) { // advance to first entry
do {} while (index < t.length && (next = t[index++]) == null);
}
}
publicfinalboolean hasNext(){
returnnext != null;
}
final Node
Node
Node
if (modCount != expectedModCount)
thrownew ConcurrentModificationException();
if (e == null)
thrownewNoSuchElementException();
if ((next = (current = e).next) == null && (t = table) != null) {
do {} while (index < t.length && (next = t[index++]) == null);
}
returne;
}
publicfinalvoid remove() {
Node
if (p == null)
thrownewIllegalStateException();
if (modCount != expectedModCount)
thrownewConcurrentModificationException();
current = null;
K key = p.key;
removeNode(hash(key), key, null, false, false);
expectedModCount = modCount;
}
}
finalclass KeyIterator extends HashIterator
implements Iterator
publicfinal K next() { return nextNode().key; }
}
finalclass ValueIterator extends HashIterator
implements Iterator
publicfinal V next() { return nextNode().value; }
}
finalclass EntryIterator extends HashIterator
implements Iterator
publicfinal Map.Entry
}
/*------------------------------------------------------------ */
// spliterators
staticclassHashMapSpliterator
final HashMap
Node
intindex; // current index, modified on advance/split
intfence; // one past last index
intest; // size estimate
intexpectedModCount; // forcomodification checks
HashMapSpliterator(HashMap
intfence, intest,
intexpectedModCount) {
this.map = m;
this.index = origin;
this.fence = fence;
this.est = est;
this.expectedModCount = expectedModCount;
}
finalint getFence() { // initialize fence and size on first use
inthi;
if ((hi = fence) < 0) {
HashMap
est = m.size;
expectedModCount = m.modCount;
Node
hi = fence = (tab == null) ? 0 : tab.length;
}
returnhi;
}
publicfinallong estimateSize() {
getFence(); // forceinit
return (long) est;
}
}
staticfinalclass KeySpliterator
extends HashMapSpliterator
implements Spliterator
KeySpliterator(HashMap
intexpectedModCount) {
super(m, origin, fence, est, expectedModCount);
}
public KeySpliterator
inthi = getFence(), lo = index, mid = (lo + hi) >>> 1;
return (lo >= mid || current != null) ? null :
new KeySpliterator<>(map, lo, index = mid, est >>>= 1,
expectedModCount);
}
publicvoid forEachRemaining(Consumer super K> action) {
inti, hi, mc;
if (action == null)
thrownew NullPointerException();
HashMap
Node
if ((hi = fence) < 0) {
mc = expectedModCount = m.modCount;
hi = fence = (tab == null) ? 0 : tab.length;
}
else
mc = expectedModCount;
if (tab != null && tab.length >= hi &&
(i = index) >= 0 && (i < (index = hi) || current != null)) {
Node
current = null;
do {
if (p == null)
p = tab[i++];
else {
action.accept(p.key);
p = p.next;
}
} while (p != null || i < hi);
if (m.modCount != mc)
thrownewConcurrentModificationException();
}
}
publicboolean tryAdvance(Consumer super K> action) {
inthi;
if (action == null)
thrownewNullPointerException();
Node
if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
while (current != null || index < hi) {
if (current == null)
current = tab[index++];
else {
K k = current.key;
current = current.next;
action.accept(k);
if (map.modCount != expectedModCount)
thrownewConcurrentModificationException();
returntrue;
}
}
}
returnfalse;
}
publicint characteristics() {
return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) |
Spliterator.DISTINCT;
}
}
staticfinalclass ValueSpliterator
extends HashMapSpliterator
implements Spliterator
ValueSpliterator(HashMap
intexpectedModCount) {
super(m, origin, fence, est, expectedModCount);
}
public ValueSpliterator
inthi = getFence(), lo = index, mid = (lo + hi) >>> 1;
return (lo >= mid || current != null) ? null :
new ValueSpliterator<>(map, lo, index = mid, est >>>= 1,
expectedModCount);
}
publicvoid forEachRemaining(Consumer super V> action) {
inti, hi, mc;
if (action == null)
thrownewNullPointerException();
HashMap
Node
if ((hi = fence) < 0) {
mc = expectedModCount = m.modCount;
hi = fence = (tab == null) ? 0 : tab.length;
}
else
mc = expectedModCount;
if (tab != null && tab.length >= hi &&
(i = index) >= 0 && (i < (index = hi) || current != null)) {
Node
current = null;
do {
if (p == null)
p = tab[i++];
else {
action.accept(p.value);
p = p.next;
}
} while (p != null || i < hi);
if (m.modCount != mc)
thrownew ConcurrentModificationException();
}
}
publicboolean tryAdvance(Consumer super V> action) {
inthi;
if (action == null)
thrownewNullPointerException();
Node
if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
while (current != null || index < hi) {
if (current == null)
current = tab[index++];
else {
V v = current.value;
current = current.next;
action.accept(v);
if (map.modCount != expectedModCount)
thrownewConcurrentModificationException();
returntrue;
}
}
}
returnfalse;
}
publicint characteristics() {
return (fence < 0 || est == map.size ? Spliterator.SIZED : 0);
}
}
staticfinalclass EntrySpliterator
extends HashMapSpliterator
implementsSpliterator
EntrySpliterator(HashMap
intexpectedModCount) {
super(m, origin, fence, est, expectedModCount);
}
public EntrySpliterator
inthi = getFence(), lo = index, mid = (lo + hi) >>> 1;
return (lo >= mid || current != null) ? null :
new EntrySpliterator<>(map, lo, index = mid, est >>>= 1,
expectedModCount);
}
publicvoid forEachRemaining(Consumer super Map.Entry
inti, hi, mc;
if (action == null)
thrownewNullPointerException();
HashMap
Node
if ((hi = fence) < 0) {
mc = expectedModCount = m.modCount;
hi = fence = (tab == null) ? 0 : tab.length;
}
else
mc = expectedModCount;
if (tab != null && tab.length >= hi &&
(i = index) >= 0 && (i < (index = hi) || current != null)) {
Node
current = null;
do {
if (p == null)
p = tab[i++];
else {
action.accept(p);
p = p.next;
}
} while (p != null || i < hi);
if (m.modCount != mc)
thrownewConcurrentModificationException();
}
}
publicboolean tryAdvance(Consumer super Map.Entry
inthi;
if (action == null)
thrownewNullPointerException();
Node
if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
while (current != null || index < hi) {
if (current == null)
current = tab[index++];
else {
Node
current = current.next;
action.accept(e);
if (map.modCount != expectedModCount)
thrownewConcurrentModificationException();
returntrue;
}
}
}
returnfalse;
}
publicint characteristics() {
return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) |
Spliterator.DISTINCT;
}
}
/* ------------------------------------------------------------*/
// LinkedHashMap support
/*
* The following package-protected methods are designed to be
* overridden by LinkedHashMap, but not by any other subclass.
* Nearly all other internal methods are also package-protected
* but are declared final, so can be used by LinkedHashMap, view
* classes, and HashSet.
*/
// Create a regular (non-tree) node
Node
returnnew Node<>(hash, key, value, next);
}
// For conversion from TreeNodes toplain nodes
Node
returnnew Node<>(p.hash, p.key, p.value, next);
}
// Create a tree bin node
TreeNode
returnnew TreeNode<>(hash, key, value, next);
}
// For treeifyBin
TreeNode
returnnew TreeNode<>(p.hash, p.key, p.value, next);
}
void reinitialize() {//设置到初始默认状态。由clone和readObject调用
table = null;
entrySet = null;
keySet = null;
values = null;
modCount = 0;
threshold = 0;
size = 0;
}
// Callbacks to allow LinkedHashMappost-actions
void afterNodeAccess(Node
void afterNodeInsertion(booleanevict) { }
void afterNodeRemoval(Node
// Called only from writeObject, toensure compatible ordering.
void internalWriteEntries(java.io.ObjectOutputStreams) throws IOException {
Node
if (size > 0 && (tab = table) != null) {
for (inti = 0; i < tab.length; ++i) {
for (Node
s.writeObject(e.key);
s.writeObject(e.value);
}
}
}
}
staticfinalclass TreeNode
TreeNode
TreeNode
TreeNode
TreeNode
booleanred;
TreeNode(inthash, K key, V val, Node
super(hash, key, val, next);
}
final TreeNode
for (TreeNode
if ((p = r.parent) == null)
returnr;
r = p;
}
}
static
intn;
if (root != null && tab != null && (n = tab.length) > 0) {
intindex = (n - 1) & root.hash;
TreeNode
if (root != first) {
Node
tab[index] = root;
TreeNode
if ((rn = root.next) != null)
((TreeNode
if (rp != null)
rp.next = rn;
if (first != null)
first.prev = root;
root.next = first;
root.prev = null;
}
assert checkInvariants(root);
}
}
1 final TreeNode
TreeNode
do {
intph, dir; K pk;
TreeNode
if ((ph = p.hash) > h)
p = pl;
elseif (ph < h)
p = pr;
elseif ((pk = p.key) == k || (k != null && k.equals(pk)))
returnp;
elseif (pl == null)
p = pr;
elseif (pr == null)
p = pl;
elseif ((kc != null ||
(kc = comparableClassFor(k)) != null) &&
(dir = compareComparables(kc, k, pk)) != 0)
p = (dir < 0) ? pl : pr;
elseif ((q = pr.find(h, k, kc)) != null)
returnq;
else
p = pl;
} while (p != null);
returnnull;
}
final TreeNode
return ((parent != null) ? root() : this).find(h, k, null);
}
/**
* Tie-breaking utility for orderinginsertions when equal
* hashCodes and non-comparable. Wedon't require a total
* order, just a consistent insertion rule to maintain
* equivalence across rebalancings. Tie-breaking further than
* necessary simplifies testing a bit.
*/
staticint tieBreakOrder(Object a, Object b) {
intd;
if (a == null || b == null ||
(d = a.getClass().getName().
compareTo(b.getClass().getName())) == 0)
d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
-1 : 1);
returnd;
}
finalvoid treeify(Node
TreeNode
for (TreeNode
next = (TreeNode
x.left = x.right = null;
if (root == null) {
x.parent = null;
x.red = false;
root = x;
}
else {
K k = x.key;
inth = x.hash;
Class> kc = null;
for (TreeNode
intdir, ph;
K pk = p.key;
if ((ph = p.hash) > h)
dir = -1;
elseif (ph < h)
dir = 1;
elseif ((kc == null &&
(kc = comparableClassFor(k)) == null) ||
(dir = compareComparables(kc, k, pk)) == 0)
dir = tieBreakOrder(k, pk);
TreeNode
if ((p = (dir <= 0) ? p.left : p.right) == null) {
x.parent = xp;
if (dir <= 0)
xp.left = x;
else
xp.right = x;
root = balanceInsertion(root, x);
break;
}
}
}
}
moveRootToFront(tab, root);
}
final Node
将以当前节点为根的所有树节点转换为普通结点
Node
for (Node
Node
if (tl == null)
hd = p;
else
tl.next = p;
tl = p;
}
returnhd;
}
final TreeNode
Class> kc = null;
booleansearched = false;
TreeNode
for (TreeNode
intdir, ph; K pk;
if ((ph = p.hash) > h)
dir = -1;
elseif (ph < h)
dir = 1;
elseif ((pk = p.key) == k || (k != null && k.equals(pk)))
returnp;
elseif ((kc == null &&
(kc = comparableClassFor(k)) == null) ||
(dir = compareComparables(kc, k, pk)) == 0) {
if (!searched) {
TreeNode
searched = true;
if (((ch = p.left) != null &&
(q = ch.find(h, k, kc)) != null) ||
((ch = p.right) != null &&
(q = ch.find(h, k, kc)) != null))
returnq;
}
dir = tieBreakOrder(k, pk);
}
TreeNode
if ((p = (dir <= 0) ? p.left : p.right) == null) {
Node
TreeNode
if (dir <= 0)
xp.left = x;
else
xp.right = x;
xp.next = x;
x.parent = x.prev = xp;
if (xpn != null)
((TreeNode
moveRootToFront(tab, balanceInsertion(root, x));
returnnull;
}
}
}
finalvoidremoveTreeNode(HashMap
intn;
if (tab == null || (n = tab.length) == 0)
return;
intindex = (n - 1) & hash;
TreeNode
TreeNode
if (pred == null)
tab[index] = first = succ;
else
pred.next = succ;
if (succ != null)
succ.prev = pred;
if (first == null)
return;
if (root.parent != null)
root = root.root();
if (root == null || root.right == null ||
(rl = root.left) == null || rl.left == null) {
tab[index] = first.untreeify(map); // too small
return;
}
TreeNode
if (pl != null && pr != null) {
TreeNode
while ((sl = s.left) != null) // find successor
s = sl;
booleanc = s.red; s.red = p.red; p.red = c; // swap colors
TreeNode
TreeNode
if (s == pr) { // p was s's direct parent
p.parent = s;
s.right = p;
}
else {
TreeNode
if ((p.parent = sp) != null) {
if (s == sp.left)
sp.left = p;
else
sp.right = p;
}
if ((s.right = pr) != null)
pr.parent = s;
}
p.left = null;
if ((p.right = sr) != null)
sr.parent = p;
if ((s.left = pl) != null)
pl.parent = s;
if ((s.parent = pp) == null)
root = s;
elseif (p == pp.left)
pp.left = s;
else
pp.right = s;
if (sr != null)
replacement = sr;
else
replacement = p;
}
elseif (pl != null)
replacement = pl;
elseif (pr != null)
replacement = pr;
else
replacement = p;
if (replacement != p) {
TreeNode
if (pp == null)
root = replacement;
elseif (p == pp.left)
pp.left = replacement;
else
pp.right = replacement;
p.left = p.right = p.parent = null;
}
TreeNode
if (replacement == p) { // detach
TreeNode
p.parent = null;
if (pp != null) {
if (p == pp.left)
pp.left = null;
elseif (p == pp.right)
pp.right = null;
}
}
if (movable)
moveRootToFront(tab, r);
}
finalvoid split(HashMap
TreeNode
// Relink intolo and hi lists, preserving order
TreeNode
TreeNode
intlc = 0, hc = 0;
for (TreeNode
next = (TreeNode
e.next = null;
if ((e.hash & bit) == 0) {
if ((e.prev = loTail) == null)
loHead = e;
else
loTail.next = e;
loTail = e;
++lc;
}
else {
if ((e.prev = hiTail) == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
++hc;
}
}
if (loHead != null) {
if (lc <= UNTREEIFY_THRESHOLD)
tab[index] = loHead.untreeify(map);
else {
tab[index] = loHead;
if (hiHead != null) // (else is already treeified)
loHead.treeify(tab);
}
}
if (hiHead != null) {
if (hc <= UNTREEIFY_THRESHOLD)
tab[index + bit] = hiHead.untreeify(map);
else {
tab[index + bit] = hiHead;
if (loHead != null)
hiHead.treeify(tab);
}
}
}
/*------------------------------------------------------------ */
//红黑树方法, 从CLR引入
static
TreeNode
if (p != null && (r = p.right) != null) {
if ((rl = p.right = r.left) != null)
rl.parent = p;
if ((pp = r.parent = p.parent) == null)
(root = r).red = false;
elseif (pp.left == p)
pp.left = r;
else
pp.right = r;
r.left = p;
p.parent = r;
}
returnroot;
}
static
TreeNode
if (p != null && (l = p.left) != null) {
if ((lr = p.left = l.right) != null)
lr.parent = p;
if ((pp = l.parent = p.parent) == null)
(root = l).red = false;
elseif (pp.right == p)
pp.right = l;
else
pp.left = l;
l.right = p;
p.parent = l;
}
returnroot;
}
static
x.red = true;
for (TreeNode
if ((xp = x.parent) == null) {
x.red = false;
returnx;
}
elseif (!xp.red || (xpp = xp.parent) == null)
returnroot;
if (xp == (xppl = xpp.left)) {
if ((xppr = xpp.right) != null && xppr.red) {
xppr.red = false;
xp.red = false;
xpp.red = true;
x = xpp;
}
else {
if (x == xp.right) {
root = rotateLeft(root, x = xp);
xpp = (xp = x.parent) == null ? null : xp.parent;
}
if (xp != null) {
xp.red = false;
if (xpp != null) {
xpp.red = true;
root = rotateRight(root, xpp);
}
}
}
}
else {
if (xppl != null && xppl.red) {
xppl.red = false;
xp.red = false;
xpp.red = true;
x = xpp;
}
else {
if (x == xp.left) {
root = rotateRight(root, x = xp);
xpp = (xp = x.parent) == null ? null : xp.parent;
}
if (xp != null) {
xp.red = false;
if (xpp != null) {
xpp.red = true;
root = rotateLeft(root, xpp);
}
}
}
}
}
}
static
for (TreeNode
if (x == null || x == root)
returnroot;
elseif ((xp = x.parent) == null) {
x.red = false;
returnx;
}
elseif (x.red) {
x.red = false;
returnroot;
}
elseif ((xpl = xp.left) == x) {
if ((xpr = xp.right) != null && xpr.red) {
xpr.red = false;
xp.red = true;
root = rotateLeft(root, xp);
xpr = (xp = x.parent) == null ? null : xp.right;
}
if (xpr == null)
x = xp;
else {
TreeNode
if ((sr == null || !sr.red) &&
(sl == null || !sl.red)) {
xpr.red = true;
x = xp;
}
else {
if (sr == null || !sr.red) {
if (sl != null)
sl.red = false;
xpr.red = true;
root = rotateRight(root, xpr);
xpr = (xp = x.parent) == null ?
null : xp.right;
}
if (xpr != null) {
xpr.red = (xp == null) ? false : xp.red;
if ((sr = xpr.right) != null)
sr.red = false;
}
if (xp != null) {
xp.red = false;
root = rotateLeft(root, xp);
}
x = root;
}
}
}
else { // symmetric
if (xpl != null && xpl.red) {
xpl.red = false;
xp.red = true;
root = rotateRight(root, xp);
xpl = (xp = x.parent) == null ? null : xp.left;
}
if (xpl == null)
x = xp;
else {
TreeNode
if ((sl == null || !sl.red) &&
(sr == null || !sr.red)) {
xpl.red = true;
x = xp;
}
else {
if (sl == null || !sl.red) {
if (sr != null)
sr.red = false;
xpl.red = true;
root = rotateLeft(root, xpl);
xpl = (xp = x.parent) == null ?
null : xp.left;
}
if (xpl != null) {
xpl.red = (xp == null) ? false : xp.red;
if ((sl = xpl.left) != null)
sl.red = false;
}
if (xp != null) {
xp.red = false;
root = rotateRight(root, xp);
}
x = root;
}
}
}
}
}
static
TreeNode
tb = t.prev, tn =(TreeNode
if (tb != null && tb.next != t)
returnfalse;
if (tn != null && tn.prev != t)
returnfalse;
if (tp != null && t != tp.left && t != tp.right)
returnfalse;
if (tl != null && (tl.parent != t || tl.hash > t.hash))
returnfalse;
if (tr != null && (tr.parent != t || tr.hash < t.hash))
returnfalse;
if (t.red && tl != null && tl.red && tr != null && tr.red)
returnfalse;
if (tl != null && !checkInvariants(tl))
returnfalse;
if (tr != null && !checkInvariants(tr))
returnfalse;
returntrue;
}
}
}