/** *Thenextsizevalueatwhichtoresize(capacity*loadfactor). * *@serial
*/ // (The javadoc description is true upon serialization. // Additionally, if the table array has not been allocated, this // field holds the initial array capacity, or zero signifying // DEFAULT_INITIAL_CAPACITY.) int threshold;
/** *ImplementsMap.putAllandMapconstructor. * *@parammthemap *@paramevictfalsewheninitiallyconstructingthismap,else *true(relayedtomethodafterNodeInsertion).
*/ finalvoid putMapEntries(Map<? extends K, ? extends V> m, boolean evict) { int s = m.size(); if (s > 0) { if (table == null) { // pre-size double dt = Math.ceil(s / (double)loadFactor); int t = ((dt < (double)MAXIMUM_CAPACITY) ?
(int)dt : MAXIMUM_CAPACITY); if (t > threshold)
threshold = tableSizeFor(t);
} else { // Because of linked-list bucket constraints, we cannot // expand all at once, but can reduce total resize // effort by repeated doubling now vs later while (s > threshold && table.length < MAXIMUM_CAPACITY)
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);
}
}
}
public Object[] toArray() { return keysToArray(new Object[size]);
}
public <T> T[] toArray(T[] a) { return keysToArray(prepareArray(a));
}
publicfinalvoid forEach(Consumer<? super K> action) {
Node<K,V>[] tab; if (action == null) thrownew NullPointerException(); if (size > 0 && (tab = table) != null) { int mc = modCount; for (Node<K,V> e : tab) { for (; e != null; e = e.next)
action.accept(e.key);
} if (modCount != mc) thrownew ConcurrentModificationException();
}
}
}
/** *Returnsa{@linkCollection}viewofthevaluescontainedinthismap. *Thecollectionisbackedbythemap,sochangestothemapare *reflectedinthecollection,andvice-versa.Ifthemapis *modifiedwhileaniterationoverthecollectionisinprogress *(exceptthroughtheiterator'sown{@coderemove}operation), *theresultsoftheiterationareundefined.Thecollection *supportselementremoval,whichremovesthecorresponding *mappingfromthemap,viathe{@codeIterator.remove}, *{@codeCollection.remove},{@coderemoveAll}, *{@coderetainAll}and{@codeclear}operations.Itdoesnot *supportthe{@codeadd}or{@codeaddAll}operations. * *@returnaviewofthevaluescontainedinthismap
*/ public Collection<V> values() {
Collection<V> vs = values; if (vs == null) {
vs = new Values();
values = vs;
} return vs;
}
public Object[] toArray() { return valuesToArray(new Object[size]);
}
public <T> T[] toArray(T[] a) { return valuesToArray(prepareArray(a));
}
publicfinalvoid forEach(Consumer<? super V> action) {
Node<K,V>[] tab; if (action == null) thrownew NullPointerException(); if (size > 0 && (tab = table) != null) { int mc = modCount; for (Node<K,V> e : tab) { for (; e != null; e = e.next)
action.accept(e.value);
} if (modCount != mc) thrownew ConcurrentModificationException();
}
}
}
@Override publicboolean replace(K key, V oldValue, V newValue) {
Node<K,V> e; V v; if ((e = getNode(key)) != null &&
((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) {
e.value = newValue;
afterNodeAccess(e); returntrue;
} returnfalse;
}
@Override public V replace(K key, V value) {
Node<K,V> e; if ((e = getNode(key)) != null) {
V oldValue = e.value;
e.value = value;
afterNodeAccess(e); return oldValue;
} returnnull;
}
/** *{@inheritDoc} * *<p>Thismethodwill,onabest-effortbasis,throwa *{@linkConcurrentModificationException}ifitisdetectedthatthe *mappingfunctionmodifiesthismapduringcomputation. * *@throwsConcurrentModificationExceptionifitisdetectedthatthe *mappingfunctionmodifiedthismap
*/
@Override public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) { if (mappingFunction == null) thrownew NullPointerException(); int hash = hash(key);
Node<K,V>[] tab; Node<K,V> first; int n, i; int binCount = 0;
TreeNode<K,V> t = null;
Node<K,V> old = null; if (size > threshold || (tab = table) == null ||
(n = tab.length) == 0)
n = (tab = resize()).length; if ((first = tab[i = (n - 1) & hash]) != null) { if (first instanceof TreeNode)
old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key); else {
Node<K,V> e = first; K k; do { if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
old = e; break;
}
++binCount;
} while ((e = e.next) != null);
}
V oldValue; if (old != null && (oldValue = old.value) != null) {
afterNodeAccess(old); return oldValue;
}
} int mc = modCount;
V v = mappingFunction.apply(key); if (mc != modCount) { thrownew ConcurrentModificationException(); } if (v == null) { returnnull;
} elseif (old != null) {
old.value = v;
afterNodeAccess(old); return v;
} elseif (t != null)
t.putTreeVal(this, tab, hash, key, v); else {
tab[i] = newNode(hash, key, v, first); if (binCount >= TREEIFY_THRESHOLD - 1)
treeifyBin(tab, hash);
}
modCount = mc + 1;
++size;
afterNodeInsertion(true); return v;
}
/** *{@inheritDoc} * *<p>Thismethodwill,onabest-effortbasis,throwa *{@linkConcurrentModificationException}ifitisdetectedthatthe *remappingfunctionmodifiesthismapduringcomputation. * *@throwsConcurrentModificationExceptionifitisdetectedthatthe *remappingfunctionmodifiedthismap
*/
@Override public V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) { if (remappingFunction == null) thrownew NullPointerException();
Node<K,V> e; V oldValue; if ((e = getNode(key)) != null &&
(oldValue = e.value) != null) { int mc = modCount;
V v = remappingFunction.apply(key, oldValue); if (mc != modCount) { thrownew ConcurrentModificationException(); } if (v != null) {
e.value = v;
afterNodeAccess(e); return v;
} else { int hash = hash(key);
removeNode(hash, key, null, false, true);
}
} returnnull;
}
/** *{@inheritDoc} * *<p>Thismethodwill,onabest-effortbasis,throwa *{@linkConcurrentModificationException}ifitisdetectedthatthe *remappingfunctionmodifiesthismapduringcomputation. * *@throwsConcurrentModificationExceptionifitisdetectedthatthe *remappingfunctionmodifiedthismap
*/
@Override public V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) { if (remappingFunction == null) thrownew NullPointerException(); int hash = hash(key);
Node<K,V>[] tab; Node<K,V> first; int n, i; int binCount = 0;
TreeNode<K,V> t = null;
Node<K,V> old = null; if (size > threshold || (tab = table) == null ||
(n = tab.length) == 0)
n = (tab = resize()).length; if ((first = tab[i = (n - 1) & hash]) != null) { if (first instanceof TreeNode)
old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key); else {
Node<K,V> e = first; K k; do { if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
old = e; break;
}
++binCount;
} while ((e = e.next) != null);
}
}
V oldValue = (old == null) ? null : old.value; int mc = modCount;
V v = remappingFunction.apply(key, oldValue); if (mc != modCount) { thrownew ConcurrentModificationException(); } if (old != null) { if (v != null) {
old.value = v;
afterNodeAccess(old);
} else
removeNode(hash, key, null, false, true);
} elseif (v != null) { if (t != null)
t.putTreeVal(this, tab, hash, key, v); else {
tab[i] = newNode(hash, key, v, first); if (binCount >= TREEIFY_THRESHOLD - 1)
treeifyBin(tab, hash);
}
modCount = mc + 1;
++size;
afterNodeInsertion(true);
} return v;
}
/** *{@inheritDoc} * *<p>Thismethodwill,onabest-effortbasis,throwa *{@linkConcurrentModificationException}ifitisdetectedthatthe *remappingfunctionmodifiesthismapduringcomputation. * *@throwsConcurrentModificationExceptionifitisdetectedthatthe *remappingfunctionmodifiedthismap
*/
@Override public V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) { if (value == null || remappingFunction == null) thrownew NullPointerException(); int hash = hash(key);
Node<K,V>[] tab; Node<K,V> first; int n, i; int binCount = 0;
TreeNode<K,V> t = null;
Node<K,V> old = null; if (size > threshold || (tab = table) == null ||
(n = tab.length) == 0)
n = (tab = resize()).length; if ((first = tab[i = (n - 1) & hash]) != null) { if (first instanceof TreeNode)
old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key); else {
Node<K,V> e = first; K k; do { if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
old = e; break;
}
++binCount;
} while ((e = e.next) != null);
}
} if (old != null) {
V v; if (old.value != null) { int mc = modCount;
v = remappingFunction.apply(old.value, value); if (mc != modCount) { thrownew ConcurrentModificationException();
}
} else {
v = value;
} if (v != null) {
old.value = v;
afterNodeAccess(old);
} else
removeNode(hash, key, null, false, true); return v;
} else { if (t != null)
t.putTreeVal(this, tab, hash, key, value); else {
tab[i] = newNode(hash, key, value, first); if (binCount >= TREEIFY_THRESHOLD - 1)
treeifyBin(tab, hash);
}
++modCount;
++size;
afterNodeInsertion(true); return value;
}
}
@Override publicvoid forEach(BiConsumer<? super K, ? super V> action) {
Node<K,V>[] tab; if (action == null) thrownew NullPointerException(); if (size > 0 && (tab = table) != null) { int mc = modCount; for (Node<K,V> e : tab) { for (; e != null; e = e.next)
action.accept(e.key, e.value);
} if (modCount != mc) thrownew ConcurrentModificationException();
}
}
@Override publicvoid replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
Node<K,V>[] tab; if (function == null) thrownew NullPointerException(); if (size > 0 && (tab = table) != null) { int mc = modCount; for (Node<K,V> e : tab) { for (; e != null; e = e.next) {
e.value = function.apply(e.key, e.value);
}
} if (modCount != mc) thrownew ConcurrentModificationException();
}
}
/* ------------------------------------------------------------ */ // Cloning and serialization
/** *Returnsashallowcopyofthis{@codeHashMap}instance:thekeysand *valuesthemselvesarenotcloned. * *@returnashallowcopyofthismap
*/
@SuppressWarnings("unchecked")
@Override public Object clone() {
HashMap<K,V> result; try {
result = (HashMap<K,V>)super.clone();
} catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable thrownew InternalError(e);
}
result.reinitialize();
result.putMapEntries(this, false); return result;
}
// These methods are also used when serializing HashSets finalfloat loadFactor() { return loadFactor; } finalint capacity() { return (table != null) ? table.length :
(threshold > 0) ? threshold :
DEFAULT_INITIAL_CAPACITY;
}
/** *Savesthismaptoastream(thatis,serializesit). * *@paramsthestream *@throwsIOExceptionifanI/Oerroroccurs *@serialDataThe<i>capacity</i>oftheHashMap(thelengthofthe *bucketarray)isemitted(int),followedbythe *<i>size</i>(anint,thenumberofkey-value *mappings),followedbythekey(Object)andvalue(Object) *foreachkey-valuemapping.Thekey-valuemappingsare *emittedinnoparticularorder.
*/
@java.io.Serial privatevoid writeObject(java.io.ObjectOutputStream s) throws IOException { int buckets = capacity(); // Write out the threshold, loadfactor, and any hidden stuff
s.defaultWriteObject();
s.writeInt(buckets);
s.writeInt(size);
internalWriteEntries(s);
}
s.readInt(); // Read and ignore number of buckets int mappings = s.readInt(); // Read number of mappings (size) if (mappings < 0) { thrownew InvalidObjectException("Illegal mappings count: " + mappings);
} elseif (mappings == 0) { // use defaults
} elseif (mappings > 0) { double dc = Math.ceil(mappings / (double)lf); int cap = ((dc < DEFAULT_INITIAL_CAPACITY) ?
DEFAULT_INITIAL_CAPACITY :
(dc >= MAXIMUM_CAPACITY) ?
MAXIMUM_CAPACITY :
tableSizeFor((int)dc)); float ft = (float)cap * lf;
threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
(int)ft : Integer.MAX_VALUE);
// Check Map.Entry[].class since it's the nearest public type to // what we're actually creating.
SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Map.Entry[].class, cap);
@SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
table = tab;
// Read the keys and values, and put the mappings in the HashMap for (int i = 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);
}
}
}
// Support for resetting final field during deserializing privatestaticfinalclass UnsafeHolder { private UnsafeHolder() { thrownew InternalError(); } privatestaticfinal jdk.internal.misc.Unsafe unsafe
= jdk.internal.misc.Unsafe.getUnsafe(); privatestaticfinallong LF_OFFSET
= unsafe.objectFieldOffset(HashMap.class, "loadFactor"); staticvoid putLoadFactor(HashMap<?, ?> map, float lf) {
unsafe.putFloat(map, LF_OFFSET, lf);
}
}
abstract class HashIterator {
Node<K,V> next; // next entry to return
Node<K,V> current; // current entry int expectedModCount; // for fast-fail int index; // current slot
HashIterator() {
expectedModCount = modCount;
Node<K,V>[] t = table;
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() { return next != null;
}
final Node<K,V> nextNode() {
Node<K,V>[] t;
Node<K,V> e = next; if (modCount != expectedModCount) thrownew ConcurrentModificationException(); if (e == null) thrownew NoSuchElementException(); if ((next = (current = e).next) == null && (t = table) != null) { do {} while (index < t.length && (next = t[index++]) == null);
} return e;
}
publicfinalvoid remove() {
Node<K,V> p = current; if (p == null) thrownew IllegalStateException(); if (modCount != expectedModCount) thrownew ConcurrentModificationException();
current = null;
removeNode(p.hash, p.key, null, false, false);
expectedModCount = modCount;
}
}
staticclass HashMapSpliterator<K,V> { final HashMap<K,V> map;
Node<K,V> current; // current node int index; // current index, modified on advance/split int fence; // one past last index int est; // size estimate int expectedModCount; // for comodification checks
HashMapSpliterator(HashMap<K,V> m, int origin, int fence, int est, int expectedModCount) { this.map = m; this.index = origin; this.fence = fence; this.est = est; this.expectedModCount = expectedModCount;
}
finalint getFence() { // initialize fence and size on first use int hi; if ((hi = fence) < 0) {
HashMap<K,V> m = map;
est = m.size;
expectedModCount = m.modCount;
Node<K,V>[] tab = m.table;
hi = fence = (tab == null) ? 0 : tab.length;
} return hi;
}
publicfinallong estimateSize() {
getFence(); // force init return (long) est;
}
}
staticfinalclass KeySpliterator<K,V> extends HashMapSpliterator<K,V> implements Spliterator<K> {
KeySpliterator(HashMap<K,V> m, int origin, int fence, int est, int expectedModCount) { super(m, origin, fence, est, expectedModCount);
}
public KeySpliterator<K,V> trySplit() { int hi = 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) { int i, hi, mc; if (action == null) thrownew NullPointerException();
HashMap<K,V> m = map;
Node<K,V>[] tab = m.table; 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<K,V> p = current;
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) thrownew ConcurrentModificationException();
}
}
publicboolean tryAdvance(Consumer<? super K> action) { int hi; if (action == null) thrownew NullPointerException();
Node<K,V>[] tab = map.table; 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) thrownew ConcurrentModificationException(); returntrue;
}
}
} returnfalse;
}
staticfinalclass ValueSpliterator<K,V> extends HashMapSpliterator<K,V> implements Spliterator<V> {
ValueSpliterator(HashMap<K,V> m, int origin, int fence, int est, int expectedModCount) { super(m, origin, fence, est, expectedModCount);
}
public ValueSpliterator<K,V> trySplit() { int hi = 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) { int i, hi, mc; if (action == null) thrownew NullPointerException();
HashMap<K,V> m = map;
Node<K,V>[] tab = m.table; 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<K,V> p = current;
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) { int hi; if (action == null) thrownew NullPointerException();
Node<K,V>[] tab = map.table; 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) thrownew ConcurrentModificationException(); returntrue;
}
}
} returnfalse;
}
staticfinalclass EntrySpliterator<K,V> extends HashMapSpliterator<K,V> implements Spliterator<Map.Entry<K,V>> {
EntrySpliterator(HashMap<K,V> m, int origin, int fence, int est, int expectedModCount) { super(m, origin, fence, est, expectedModCount);
}
public EntrySpliterator<K,V> trySplit() { int hi = 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<K,V>> action) { int i, hi, mc; if (action == null) thrownew NullPointerException();
HashMap<K,V> m = map;
Node<K,V>[] tab = m.table; 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<K,V> p = current;
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) thrownew ConcurrentModificationException();
}
}
publicboolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) { int hi; if (action == null) thrownew NullPointerException();
Node<K,V>[] tab = map.table; if (tab != null && tab.length >= (hi = getFence()) && index >= 0) { while (current != null || index < hi) { if (current == null)
current = tab[index++]; else {
Node<K,V> e = current;
current = current.next;
action.accept(e); if (map.modCount != expectedModCount) thrownew ConcurrentModificationException(); returntrue;
}
}
} returnfalse;
}
// Called only from writeObject, to ensure compatible ordering. void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
Node<K,V>[] tab; if (size > 0 && (tab = table) != null) { for (Node<K,V> e : tab) { for (; e != null; e = e.next) {
s.writeObject(e.key);
s.writeObject(e.value);
}
}
}
}
/* ------------------------------------------------------------ */ // Tree bins
/** *EntryforTreebins.ExtendsLinkedHashMap.Entry(whichinturn *extendsNode)socanbeusedasextensionofeitherregularor *linkednode.
*/ staticfinalclass TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
TreeNode<K,V> parent; // red-black tree links
TreeNode<K,V> left;
TreeNode<K,V> right;
TreeNode<K,V> prev; // needed to unlink next upon deletion boolean red;
TreeNode(int hash, K key, V val, Node<K,V> next) { super(hash, key, val, next);
}
/** *Returnsrootoftreecontainingthisnode.
*/ final TreeNode<K,V> root() { for (TreeNode<K,V> r = this, p;;) { if ((p = r.parent) == null) return r;
r = p;
}
}
/** *Ensuresthatthegivenrootisthefirstnodeofitsbin.
*/ static <K,V> void moveRootToFront(Node<K,V>[] tab, TreeNode<K,V> root) { int n; if (root != null && tab != null && (n = tab.length) > 0) { int index = (n - 1) & root.hash;
TreeNode<K,V> first = (TreeNode<K,V>)tab[index]; if (root != first) {
Node<K,V> rn;
tab[index] = root;
TreeNode<K,V> rp = root.prev; if ((rn = root.next) != null)
((TreeNode<K,V>)rn).prev = rp; if (rp != null)
rp.next = rn; if (first != null)
first.prev = root;
root.next = first;
root.prev = null;
} assert checkInvariants(root);
}
}
/** *Findsthenodestartingatrootpwiththegivenhashandkey. *ThekcargumentcachescomparableClassFor(key)uponfirstuse *comparingkeys.
*/ final TreeNode<K,V> find(int h, Object k, Class<?> kc) {
TreeNode<K,V> p = this; do { int ph, dir; K pk;
TreeNode<K,V> pl = p.left, pr = p.right, q; if ((ph = p.hash) > h)
p = pl; elseif (ph < h)
p = pr; elseif ((pk = p.key) == k || (k != null && k.equals(pk))) return p; 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) return q; else
p = pl;
} while (p != null); returnnull;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.