2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 // Completely different implementation from harmony. Runs much faster.
24 import java.io.IOException;
25 import java.io.InvalidObjectException;
26 import java.io.ObjectInputStream;
27 import java.io.ObjectOutputStream;
28 import java.io.ObjectStreamField;
29 import java.io.Serializable;
30 import libcore.base.Objects;
33 * HashMap is an implementation of {@link Map}. All optional operations are supported.
35 * <p>All elements are permitted as keys or values, including null.
37 * <p>Note that the iteration order for HashMap is non-deterministic. If you want
38 * deterministic iteration, use {@link LinkedHashMap}.
40 * <p>Note: the implementation of {@code HashMap} is not synchronized.
41 * If one thread of several threads accessing an instance modifies the map
42 * structurally, access to the map needs to be synchronized. A structural
43 * modification is an operation that adds or removes an entry. Changes in
44 * the value of an entry are not structural changes.
46 * <p>The {@code Iterator} created by calling the {@code iterator} method
47 * may throw a {@code ConcurrentModificationException} if the map is structurally
48 * changed while an iterator is used to iterate over the elements. Only the
49 * {@code remove} method that is provided by the iterator allows for removal of
50 * elements during iteration. It is not possible to guarantee that this
51 * mechanism works in all cases of unsynchronized concurrent modification. It
52 * should only be used for debugging purposes.
54 * @param <K> the type of keys maintained by this map
55 * @param <V> the type of mapped values
57 public class HashMap<K, V> extends AbstractMap<K, V> implements Cloneable, Serializable {
59 * Min capacity (other than zero) for a HashMap. Must be a power of two
60 * greater than 1 (and less than 1 << 30).
62 private static final int MINIMUM_CAPACITY = 4;
65 * Max capacity for a HashMap. Must be a power of two >= MINIMUM_CAPACITY.
67 private static final int MAXIMUM_CAPACITY = 1 << 30;
70 * An empty table shared by all zero-capacity maps (typically from default
71 * constructor). It is never written to, and replaced on first put. Its size
72 * is set to half the minimum, so that the first resize will create a
73 * minimum-sized table.
75 private static final Entry[] EMPTY_TABLE
76 = new HashMapEntry[MINIMUM_CAPACITY >>> 1];
79 * The default load factor. Note that this implementation ignores the
80 * load factor, but cannot do away with it entirely because it's
81 * mentioned in the API.
83 * <p>Note that this constant has no impact on the behavior of the program,
84 * but it is emitted as part of the serialized form. The load factor of
85 * .75 is hardwired into the program, which uses cheap shifts in place of
88 static final float DEFAULT_LOAD_FACTOR = .75F;
91 * The hash table. If this hash map contains a mapping for null, it is
92 * not represented this hash table.
94 transient HashMapEntry<K, V>[] table;
97 * The entry representing the null key, or null if there's no such mapping.
99 transient HashMapEntry<K, V> entryForNullKey;
102 * The number of mappings in this hash map.
107 * Incremented by "structural modifications" to allow (best effort)
108 * detection of concurrent modification.
110 transient int modCount;
113 * The table is rehashed when its size exceeds this threshold.
114 * The value of this field is generally .75 * capacity, except when
115 * the capacity is zero, as described in the EMPTY_TABLE declaration
118 private transient int threshold;
120 // Views - lazily initialized
121 private transient Set<K> keySet;
122 private transient Set<Entry<K, V>> entrySet;
123 private transient Collection<V> values;
126 * Constructs a new empty {@code HashMap} instance.
128 @SuppressWarnings("unchecked")
130 table = (HashMapEntry<K, V>[]) EMPTY_TABLE;
131 threshold = -1; // Forces first put invocation to replace EMPTY_TABLE
135 * Constructs a new {@code HashMap} instance with the specified capacity.
138 * the initial capacity of this hash map.
139 * @throws IllegalArgumentException
140 * when the capacity is less than zero.
142 public HashMap(int capacity) {
144 throw new IllegalArgumentException("Capacity: " + capacity);
148 @SuppressWarnings("unchecked")
149 HashMapEntry<K, V>[] tab = (HashMapEntry<K, V>[]) EMPTY_TABLE;
151 threshold = -1; // Forces first put() to replace EMPTY_TABLE
155 if (capacity < MINIMUM_CAPACITY) {
156 capacity = MINIMUM_CAPACITY;
157 } else if (capacity > MAXIMUM_CAPACITY) {
158 capacity = MAXIMUM_CAPACITY;
160 capacity = roundUpToPowerOfTwo(capacity);
166 * Constructs a new {@code HashMap} instance with the specified capacity and
170 * the initial capacity of this hash map.
172 * the initial load factor.
173 * @throws IllegalArgumentException
174 * when the capacity is less than zero or the load factor is
175 * less or equal to zero or NaN.
177 public HashMap(int capacity, float loadFactor) {
180 if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
181 throw new IllegalArgumentException("Load factor: " + loadFactor);
185 * Note that this implementation ignores loadFactor; it always uses
186 * a load factor of 3/4. This simplifies the code and generally
187 * improves performance.
192 * Constructs a new {@code HashMap} instance containing the mappings from
196 * the mappings to add.
198 public HashMap(Map<? extends K, ? extends V> map) {
199 this(capacityForInitSize(map.size()));
200 constructorPutAll(map);
204 * Inserts all of the elements of map into this HashMap in a manner
205 * suitable for use by constructors and pseudo-constructors (i.e., clone,
206 * readObject). Also used by LinkedHashMap.
208 final void constructorPutAll(Map<? extends K, ? extends V> map) {
209 for (Entry<? extends K, ? extends V> e : map.entrySet()) {
210 constructorPut(e.getKey(), e.getValue());
215 * Returns an appropriate capacity for the specified initial size. Does
216 * not round the result up to a power of two; the caller must do this!
217 * The returned value will be between 0 and MAXIMUM_CAPACITY (inclusive).
219 static int capacityForInitSize(int size) {
220 int result = (size >> 1) + size; // Multiply by 3/2 to allow for growth
222 // boolean expr is equivalent to result >= 0 && result<MAXIMUM_CAPACITY
223 return (result & ~(MAXIMUM_CAPACITY-1))==0 ? result : MAXIMUM_CAPACITY;
227 * Returns a shallow copy of this map.
229 * @return a shallow copy of this map.
231 @SuppressWarnings("unchecked")
232 @Override public Object clone() {
234 * This could be made more efficient. It unnecessarily hashes all of
235 * the elements in the map.
237 HashMap<K, V> result;
239 result = (HashMap<K, V>) super.clone();
240 } catch (CloneNotSupportedException e) {
241 throw new AssertionError(e);
244 // Restore clone to empty state, retaining our capacity and threshold
245 result.makeTable(table.length);
246 result.entryForNullKey = null;
248 result.keySet = null;
249 result.entrySet = null;
250 result.values = null;
252 result.init(); // Give subclass a chance to initialize itself
253 result.constructorPutAll(this); // Calls method overridden in subclass!!
258 * This method is called from the pseudo-constructors (clone and readObject)
259 * prior to invoking constructorPut/constructorPutAll, which invoke the
260 * overridden constructorNewEntry method. Normally it is a VERY bad idea to
261 * invoke an overridden method from a pseudo-constructor (Effective Java
262 * Item 17). In this case it is unavoidable, and the init method provides a
268 * Returns whether this map is empty.
270 * @return {@code true} if this map has no elements, {@code false}
274 @Override public boolean isEmpty() {
279 * Returns the number of elements in this map.
281 * @return the number of elements in this map.
283 @Override public int size() {
288 * Returns the value of the mapping with the specified key.
292 * @return the value of the mapping with the specified key, or {@code null}
293 * if no mapping for the specified key is found.
295 public V get(Object key) {
297 HashMapEntry<K, V> e = entryForNullKey;
298 return e == null ? null : e.value;
301 // Doug Lea's supplemental secondaryHash function (inlined)
302 int hash = key.hashCode();
303 hash ^= (hash >>> 20) ^ (hash >>> 12);
304 hash ^= (hash >>> 7) ^ (hash >>> 4);
306 HashMapEntry<K, V>[] tab = table;
307 for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)];
308 e != null; e = e.next) {
310 if (eKey == key || (e.hash == hash && key.equals(eKey))) {
318 * Returns whether this map contains the specified key.
321 * the key to search for.
322 * @return {@code true} if this map contains the specified key,
323 * {@code false} otherwise.
325 @Override public boolean containsKey(Object key) {
327 return entryForNullKey != null;
330 // Doug Lea's supplemental secondaryHash function (inlined)
331 int hash = key.hashCode();
332 hash ^= (hash >>> 20) ^ (hash >>> 12);
333 hash ^= (hash >>> 7) ^ (hash >>> 4);
335 HashMapEntry<K, V>[] tab = table;
336 for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)];
337 e != null; e = e.next) {
339 if (eKey == key || (e.hash == hash && key.equals(eKey))) {
347 * Returns whether this map contains the specified value.
350 * the value to search for.
351 * @return {@code true} if this map contains the specified value,
352 * {@code false} otherwise.
354 @Override public boolean containsValue(Object value) {
355 HashMapEntry[] tab = table;
356 int len = tab.length;
358 for (int i = 0; i < len; i++) {
359 for (HashMapEntry e = tab[i]; e != null; e = e.next) {
360 if (e.value == null) {
365 return entryForNullKey != null && entryForNullKey.value == null;
369 for (int i = 0; i < len; i++) {
370 for (HashMapEntry e = tab[i]; e != null; e = e.next) {
371 if (value.equals(e.value)) {
376 return entryForNullKey != null && value.equals(entryForNullKey.value);
380 * Maps the specified key to the specified value.
386 * @return the value of any previous mapping with the specified key or
387 * {@code null} if there was no such mapping.
389 @Override public V put(K key, V value) {
391 return putValueForNullKey(value);
394 int hash = secondaryHash(key.hashCode());
395 HashMapEntry<K, V>[] tab = table;
396 int index = hash & (tab.length - 1);
397 for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {
398 if (e.hash == hash && key.equals(e.key)) {
400 V oldValue = e.value;
406 // No entry for (non-null) key is present; create one
408 if (size++ > threshold) {
409 tab = doubleCapacity();
410 index = hash & (tab.length - 1);
412 addNewEntry(key, value, hash, index);
416 private V putValueForNullKey(V value) {
417 HashMapEntry<K, V> entry = entryForNullKey;
419 addNewEntryForNullKey(value);
425 V oldValue = entry.value;
432 * Give LinkedHashMap a chance to take action when we modify an existing
435 * @param e the entry we're about to modify.
437 void preModify(HashMapEntry<K, V> e) { }
440 * This method is just like put, except that it doesn't do things that
441 * are inappropriate or unnecessary for constructors and pseudo-constructors
442 * (i.e., clone, readObject). In particular, this method does not check to
443 * ensure that capacity is sufficient, and does not increment modCount.
445 private void constructorPut(K key, V value) {
447 HashMapEntry<K, V> entry = entryForNullKey;
449 entryForNullKey = constructorNewEntry(null, value, 0, null);
457 int hash = secondaryHash(key.hashCode());
458 HashMapEntry<K, V>[] tab = table;
459 int index = hash & (tab.length - 1);
460 HashMapEntry<K, V> first = tab[index];
461 for (HashMapEntry<K, V> e = first; e != null; e = e.next) {
462 if (e.hash == hash && key.equals(e.key)) {
468 // No entry for (non-null) key is present; create one
469 tab[index] = constructorNewEntry(key, value, hash, first);
474 * Creates a new entry for the given key, value, hash, and index and
475 * inserts it into the hash table. This method is called by put
476 * (and indirectly, putAll), and overridden by LinkedHashMap. The hash
477 * must incorporate the secondary hash function.
479 void addNewEntry(K key, V value, int hash, int index) {
480 table[index] = new HashMapEntry<K, V>(key, value, hash, table[index]);
484 * Creates a new entry for the null key, and the given value and
485 * inserts it into the hash table. This method is called by put
486 * (and indirectly, putAll), and overridden by LinkedHashMap.
488 void addNewEntryForNullKey(V value) {
489 entryForNullKey = new HashMapEntry<K, V>(null, value, 0, null);
493 * Like newEntry, but does not perform any activity that would be
494 * unnecessary or inappropriate for constructors. In this class, the
495 * two methods behave identically; in LinkedHashMap, they differ.
497 HashMapEntry<K, V> constructorNewEntry(
498 K key, V value, int hash, HashMapEntry<K, V> first) {
499 return new HashMapEntry<K, V>(key, value, hash, first);
503 * Copies all the mappings in the specified map to this map. These mappings
504 * will replace all mappings that this map had for any of the keys currently
508 * the map to copy mappings from.
510 @Override public void putAll(Map<? extends K, ? extends V> map) {
511 ensureCapacity(map.size());
516 * Ensures that the hash table has sufficient capacity to store the
517 * specified number of mappings, with room to grow. If not, it increases the
518 * capacity as appropriate. Like doubleCapacity, this method moves existing
519 * entries to new buckets as appropriate. Unlike doubleCapacity, this method
520 * can grow the table by factors of 2^n for n > 1. Hopefully, a single call
521 * to this method will be faster than multiple calls to doubleCapacity.
523 * <p>This method is called only by putAll.
525 private void ensureCapacity(int numMappings) {
526 int newCapacity = roundUpToPowerOfTwo(capacityForInitSize(numMappings));
527 HashMapEntry<K, V>[] oldTable = table;
528 int oldCapacity = oldTable.length;
529 if (newCapacity <= oldCapacity) {
532 if (newCapacity == oldCapacity << 1) {
537 // We're growing by at least 4x, rehash in the obvious way
538 HashMapEntry<K, V>[] newTable = makeTable(newCapacity);
540 int newMask = newCapacity - 1;
541 for (int i = 0; i < oldCapacity; i++) {
542 for (HashMapEntry<K, V> e = oldTable[i]; e != null;) {
543 HashMapEntry<K, V> oldNext = e.next;
544 int newIndex = e.hash & newMask;
545 HashMapEntry<K, V> newNext = newTable[newIndex];
546 newTable[newIndex] = e;
555 * Allocate a table of the given capacity and set the threshold accordingly.
556 * @param newCapacity must be a power of two
558 private HashMapEntry<K, V>[] makeTable(int newCapacity) {
559 @SuppressWarnings("unchecked") HashMapEntry<K, V>[] newTable
560 = (HashMapEntry<K, V>[]) new HashMapEntry[newCapacity];
562 threshold = (newCapacity >> 1) + (newCapacity >> 2); // 3/4 capacity
567 * Doubles the capacity of the hash table. Existing entries are placed in
568 * the correct bucket on the enlarged table. If the current capacity is,
569 * MAXIMUM_CAPACITY, this method is a no-op. Returns the table, which
570 * will be new unless we were already at MAXIMUM_CAPACITY.
572 private HashMapEntry<K, V>[] doubleCapacity() {
573 HashMapEntry<K, V>[] oldTable = table;
574 int oldCapacity = oldTable.length;
575 if (oldCapacity == MAXIMUM_CAPACITY) {
578 int newCapacity = oldCapacity << 1;
579 HashMapEntry<K, V>[] newTable = makeTable(newCapacity);
584 for (int j = 0; j < oldCapacity; j++) {
586 * Rehash the bucket using the minimum number of field writes.
587 * This is the most subtle and delicate code in the class.
589 HashMapEntry<K, V> e = oldTable[j];
593 int highBit = e.hash & oldCapacity;
594 HashMapEntry<K, V> broken = null;
595 newTable[j | highBit] = e;
596 for (HashMapEntry<K, V> n = e.next; n != null; e = n, n = n.next) {
597 int nextHighBit = n.hash & oldCapacity;
598 if (nextHighBit != highBit) {
600 newTable[j | nextHighBit] = n;
604 highBit = nextHighBit;
614 * Removes the mapping with the specified key from this map.
617 * the key of the mapping to remove.
618 * @return the value of the removed mapping or {@code null} if no mapping
619 * for the specified key was found.
621 @Override public V remove(Object key) {
623 return removeNullKey();
625 int hash = secondaryHash(key.hashCode());
626 HashMapEntry<K, V>[] tab = table;
627 int index = hash & (tab.length - 1);
628 for (HashMapEntry<K, V> e = tab[index], prev = null;
629 e != null; prev = e, e = e.next) {
630 if (e.hash == hash && key.equals(e.key)) {
645 private V removeNullKey() {
646 HashMapEntry<K, V> e = entryForNullKey;
650 entryForNullKey = null;
658 * Subclass overrides this method to unlink entry.
660 void postRemove(HashMapEntry<K, V> e) { }
663 * Removes all mappings from this hash map, leaving it empty.
668 @Override public void clear() {
670 Arrays.fill(table, null);
671 entryForNullKey = null;
678 * Returns a set of the keys contained in this map. The set is backed by
679 * this map so changes to one are reflected by the other. The set does not
682 * @return a set of the keys.
684 @Override public Set<K> keySet() {
686 return (ks != null) ? ks : (keySet = new KeySet());
690 * Returns a collection of the values contained in this map. The collection
691 * is backed by this map so changes to one are reflected by the other. The
692 * collection supports remove, removeAll, retainAll and clear operations,
693 * and it does not support add or addAll operations.
695 * This method returns a collection which is the subclass of
696 * AbstractCollection. The iterator method of this subclass returns a
697 * "wrapper object" over the iterator of map's entrySet(). The {@code size}
698 * method wraps the map's size method and the {@code contains} method wraps
699 * the map's containsValue method.
702 * The collection is created when this method is called for the first time
703 * and returned in response to all subsequent calls. This method may return
704 * different collections when multiple concurrent calls occur, since no
705 * synchronization is performed.
708 * @return a collection of the values contained in this map.
710 @Override public Collection<V> values() {
711 Collection<V> vs = values;
712 return (vs != null) ? vs : (values = new Values());
716 * Returns a set containing all of the mappings in this map. Each mapping is
717 * an instance of {@link Map.Entry}. As the set is backed by this map,
718 * changes in one will be reflected in the other.
720 * @return a set of the mappings.
722 public Set<Entry<K, V>> entrySet() {
723 Set<Entry<K, V>> es = entrySet;
724 return (es != null) ? es : (entrySet = new EntrySet());
727 static class HashMapEntry<K, V> implements Entry<K, V> {
731 HashMapEntry<K, V> next;
733 HashMapEntry(K key, V value, int hash, HashMapEntry<K, V> next) {
740 public final K getKey() {
744 public final V getValue() {
748 public final V setValue(V value) {
749 V oldValue = this.value;
754 @Override public final boolean equals(Object o) {
755 if (!(o instanceof Entry)) {
758 Entry<?, ?> e = (Entry<?, ?>) o;
759 return Objects.equal(e.getKey(), key)
760 && Objects.equal(e.getValue(), value);
763 @Override public final int hashCode() {
764 return (key == null ? 0 : key.hashCode()) ^
765 (value == null ? 0 : value.hashCode());
768 @Override public final String toString() {
769 return key + "=" + value;
773 private abstract class HashIterator {
775 HashMapEntry<K, V> nextEntry = entryForNullKey;
776 HashMapEntry<K, V> lastEntryReturned;
777 int expectedModCount = modCount;
780 if (nextEntry == null) {
781 HashMapEntry<K, V>[] tab = table;
782 HashMapEntry<K, V> next = null;
783 while (next == null && nextIndex < tab.length) {
784 next = tab[nextIndex++];
790 public boolean hasNext() {
791 return nextEntry != null;
794 HashMapEntry<K, V> nextEntry() {
795 if (modCount != expectedModCount)
796 throw new ConcurrentModificationException();
797 if (nextEntry == null)
798 throw new NoSuchElementException();
800 HashMapEntry<K, V> entryToReturn = nextEntry;
801 HashMapEntry<K, V>[] tab = table;
802 HashMapEntry<K, V> next = entryToReturn.next;
803 while (next == null && nextIndex < tab.length) {
804 next = tab[nextIndex++];
807 return lastEntryReturned = entryToReturn;
810 public void remove() {
811 if (lastEntryReturned == null)
812 throw new IllegalStateException();
813 if (modCount != expectedModCount)
814 throw new ConcurrentModificationException();
815 HashMap.this.remove(lastEntryReturned.key);
816 lastEntryReturned = null;
817 expectedModCount = modCount;
821 private final class KeyIterator extends HashIterator
822 implements Iterator<K> {
823 public K next() { return nextEntry().key; }
826 private final class ValueIterator extends HashIterator
827 implements Iterator<V> {
828 public V next() { return nextEntry().value; }
831 private final class EntryIterator extends HashIterator
832 implements Iterator<Entry<K, V>> {
833 public Entry<K, V> next() { return nextEntry(); }
837 * Returns true if this map contains the specified mapping.
839 private boolean containsMapping(Object key, Object value) {
841 HashMapEntry<K, V> e = entryForNullKey;
842 return e != null && Objects.equal(value, e.value);
845 int hash = secondaryHash(key.hashCode());
846 HashMapEntry<K, V>[] tab = table;
847 int index = hash & (tab.length - 1);
848 for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {
849 if (e.hash == hash && key.equals(e.key)) {
850 return Objects.equal(value, e.value);
853 return false; // No entry for key
857 * Removes the mapping from key to value and returns true if this mapping
858 * exists; otherwise, returns does nothing and returns false.
860 private boolean removeMapping(Object key, Object value) {
862 HashMapEntry<K, V> e = entryForNullKey;
863 if (e == null || !Objects.equal(value, e.value)) {
866 entryForNullKey = null;
873 int hash = secondaryHash(key.hashCode());
874 HashMapEntry<K, V>[] tab = table;
875 int index = hash & (tab.length - 1);
876 for (HashMapEntry<K, V> e = tab[index], prev = null;
877 e != null; prev = e, e = e.next) {
878 if (e.hash == hash && key.equals(e.key)) {
879 if (!Objects.equal(value, e.value)) {
880 return false; // Map has wrong value for key
893 return false; // No entry for key
896 // Subclass (LinkedHashMap) overrides these for correct iteration order
897 Iterator<K> newKeyIterator() { return new KeyIterator(); }
898 Iterator<V> newValueIterator() { return new ValueIterator(); }
899 Iterator<Entry<K, V>> newEntryIterator() { return new EntryIterator(); }
901 private final class KeySet extends AbstractSet<K> {
902 public Iterator<K> iterator() {
903 return newKeyIterator();
908 public boolean isEmpty() {
911 public boolean contains(Object o) {
912 return containsKey(o);
914 public boolean remove(Object o) {
916 HashMap.this.remove(o);
917 return size != oldSize;
919 public void clear() {
920 HashMap.this.clear();
924 private final class Values extends AbstractCollection<V> {
925 public Iterator<V> iterator() {
926 return newValueIterator();
931 public boolean isEmpty() {
934 public boolean contains(Object o) {
935 return containsValue(o);
937 public void clear() {
938 HashMap.this.clear();
942 private final class EntrySet extends AbstractSet<Entry<K, V>> {
943 public Iterator<Entry<K, V>> iterator() {
944 return newEntryIterator();
946 public boolean contains(Object o) {
947 if (!(o instanceof Entry))
949 Entry<?, ?> e = (Entry<?, ?>) o;
950 return containsMapping(e.getKey(), e.getValue());
952 public boolean remove(Object o) {
953 if (!(o instanceof Entry))
955 Entry<?, ?> e = (Entry<?, ?>)o;
956 return removeMapping(e.getKey(), e.getValue());
961 public boolean isEmpty() {
964 public void clear() {
965 HashMap.this.clear();
970 * Applies a supplemental hash function to a given hashCode, which defends
971 * against poor quality hash functions. This is critical because HashMap
972 * uses power-of-two length hash tables, that otherwise encounter collisions
973 * for hashCodes that do not differ in lower or upper bits.
975 private static int secondaryHash(int h) {
976 // Doug Lea's supplemental hash function
977 h ^= (h >>> 20) ^ (h >>> 12);
978 return h ^ (h >>> 7) ^ (h >>> 4);
982 * Returns the smallest power of two >= its argument, with several caveats:
983 * If the argument is negative but not Integer.MIN_VALUE, the method returns
984 * zero. If the argument is > 2^30 or equal to Integer.MIN_VALUE, the method
985 * returns Integer.MIN_VALUE. If the argument is zero, the method returns
988 private static int roundUpToPowerOfTwo(int i) {
989 i--; // If input is a power of two, shift its high-order bit right
991 // "Smear" the high-order bit all the way to the right
1001 private static final long serialVersionUID = 362498820763181265L;
1004 * Serializable fields.
1006 * @serialField loadFactor float
1007 * load factor for this HashMap
1009 private static final ObjectStreamField[] serialPersistentFields = {
1010 new ObjectStreamField("loadFactor", Float.TYPE)
1013 private void writeObject(ObjectOutputStream stream) throws IOException {
1014 // Emulate loadFactor field for other implementations to read
1015 ObjectOutputStream.PutField fields = stream.putFields();
1016 fields.put("loadFactor", DEFAULT_LOAD_FACTOR);
1017 stream.writeFields();
1019 stream.writeInt(table.length); // Capacity
1020 stream.writeInt(size);
1021 for (Entry<K, V> e : entrySet()) {
1022 stream.writeObject(e.getKey());
1023 stream.writeObject(e.getValue());
1027 private void readObject(ObjectInputStream stream) throws IOException,
1028 ClassNotFoundException {
1029 stream.defaultReadObject();
1030 int capacity = stream.readInt();
1032 throw new InvalidObjectException("Capacity: " + capacity);
1034 if (capacity < MINIMUM_CAPACITY) {
1035 capacity = MINIMUM_CAPACITY;
1036 } else if (capacity > MAXIMUM_CAPACITY) {
1037 capacity = MAXIMUM_CAPACITY;
1039 capacity = roundUpToPowerOfTwo(capacity);
1041 makeTable(capacity);
1043 int size = stream.readInt();
1045 throw new InvalidObjectException("Size: " + size);
1048 init(); // Give subclass (LinkedHashMap) a chance to initialize itself
1049 for (int i = 0; i < size; i++) {
1050 @SuppressWarnings("unchecked") K key = (K) stream.readObject();
1051 @SuppressWarnings("unchecked") V val = (V) stream.readObject();
1052 constructorPut(key, val);