identityhashmap.java
来自「This is a resource based on j2me embedde」· Java 代码 · 共 1,187 行 · 第 1/3 页
JAVA
1,187 行
if (item == k) return tab[i + 1] == value; if (item == null) return false; i = nextKeyIndex(i, len); } } /** * Associates the specified value with the specified key in this identity * hash map. If the map previously contained a mapping for this key, the * old value is replaced. * * @param key the key with which the specified value is to be associated. * @param value the value to be associated with the specified key. * @return the previous value associated with <tt>key</tt>, or * <tt>null</tt> if there was no mapping for <tt>key</tt>. (A * <tt>null</tt> return can also indicate that the map previously * associated <tt>null</tt> with the specified key.) * @see Object#equals(Object) * @see #get(Object) * @see #containsKey(Object) */ public Object put(Object key, Object value) { Object k = maskNull(key); Object[] tab = table; int len = tab.length; int i = hash(k, len); Object item; while ( (item = tab[i]) != null) { if (item == k) { Object oldValue = tab[i + 1]; tab[i + 1] = value; return oldValue; } i = nextKeyIndex(i, len); } modCount++; tab[i] = k; tab[i + 1] = value; if (++size >= threshold) resize(len); // len == 2 * current capacity. return null; } /** * Resize the table to hold given capacity. * * @param newCapacity the new capacity, must be a power of two. */ private void resize(int newCapacity) { // assert (newCapacity & -newCapacity) == newCapacity; // power of 2 int newLength = newCapacity * 2; Object[] oldTable = table; int oldLength = oldTable.length; if (oldLength == 2*MAXIMUM_CAPACITY) { // can't expand any further if (threshold == MAXIMUM_CAPACITY-1) throw new IllegalStateException("Capacity exhausted."); threshold = MAXIMUM_CAPACITY-1; // Gigantic map! return; } if (oldLength >= newLength) return; Object[] newTable = new Object[newLength]; threshold = newLength / 3; for (int j = 0; j < oldLength; j += 2) { Object key = oldTable[j]; if (key != null) { Object value = oldTable[j+1]; oldTable[j] = null; oldTable[j+1] = null; int i = hash(key, newLength); while (newTable[i] != null) i = nextKeyIndex(i, newLength); newTable[i] = key; newTable[i + 1] = value; } } table = newTable; } /** * Copies all of the mappings from the specified map to this map * These mappings will replace any mappings that * this map had for any of the keys currently in the specified map.<p> * * @param t mappings to be stored in this map. * @throws NullPointerException if the specified map is null. */ public void putAll(Map t) { int n = t.size(); if (n == 0) return; if (n > threshold) // conservatively pre-expand resize(capacity(n)); for (Iterator it = t.entrySet().iterator(); it.hasNext(); ) { Entry e = (Entry) it.next(); put(e.getKey(), e.getValue()); } } /** * Removes the mapping for this key from this map if present. * * @param key key whose mapping is to be removed from the map. * @return previous value associated with specified key, or <tt>null</tt> * if there was no entry for key. (A <tt>null</tt> return can * also indicate that the map previously associated <tt>null</tt> * with the specified key.) */ public Object remove(Object key) { Object k = maskNull(key); Object[] tab = table; int len = tab.length; int i = hash(k, len); while (true) { Object item = tab[i]; if (item == k) { modCount++; size--; Object oldValue = tab[i + 1]; tab[i + 1] = null; tab[i] = null; closeDeletion(i); return oldValue; } if (item == null) return null; i = nextKeyIndex(i, len); } } /** * Removes the specified key-value mapping from the map if it is present. * * @param key possible key. * @param value possible value. * @return <code>true</code> if and only if the specified key-value * mapping was in map. */ private boolean removeMapping(Object key, Object value) { Object k = maskNull(key); Object[] tab = table; int len = tab.length; int i = hash(k, len); while (true) { Object item = tab[i]; if (item == k) { if (tab[i + 1] != value) return false; modCount++; size--; tab[i] = null; tab[i + 1] = null; closeDeletion(i); return true; } if (item == null) return false; i = nextKeyIndex(i, len); } } /** * Rehash all possibly-colliding entries following a * deletion. This preserves the linear-probe * collision properties required by get, put, etc. * * @param d the index of a newly empty deleted slot */ private void closeDeletion(int d) { // Adapted from Knuth Section 6.4 Algorithm R Object[] tab = table; int len = tab.length; // Look for items to swap into newly vacated slot // starting at index immediately following deletion, // and continuing until a null slot is seen, indicating // the end of a run of possibly-colliding keys. Object item; for (int i = nextKeyIndex(d, len); (item = tab[i]) != null; i = nextKeyIndex(i, len) ) { // The following test triggers if the item at slot i (which // hashes to be at slot r) should take the spot vacated by d. // If so, we swap it in, and then continue with d now at the // newly vacated i. This process will terminate when we hit // the null slot at the end of this run. // The test is messy because we are using a circular table. int r = hash(item, len); if ((i < r && (r <= d || d <= i)) || (r <= d && d <= i)) { tab[d] = item; tab[d + 1] = tab[i + 1]; tab[i] = null; tab[i + 1] = null; d = i; } } } /** * Removes all mappings from this map. */ public void clear() { modCount++; Object[] tab = table; for (int i = 0; i < tab.length; i++) tab[i] = null; size = 0; } /** * Compares the specified object with this map for equality. Returns * <tt>true</tt> if the given object is also a map and the two maps * represent identical object-reference mappings. More formally, this * map is equal to another map <tt>m</tt> if and only if * map <tt>this.entrySet().equals(m.entrySet())</tt>. * * <p><b>Owing to the reference-equality-based semantics of this map it is * possible that the symmetry and transitivity requirements of the * <tt>Object.equals</tt> contract may be violated if this map is compared * to a normal map. However, the <tt>Object.equals</tt> contract is * guaranteed to hold among <tt>IdentityHashMap</tt> instances.</b> * * @param o object to be compared for equality with this map. * @return <tt>true</tt> if the specified object is equal to this map. * @see Object#equals(Object) */ public boolean equals(Object o) { if (o == this) { return true; } else if (o instanceof IdentityHashMap) { IdentityHashMap m = (IdentityHashMap) o; if (m.size() != size) return false; Object[] tab = m.table; for (int i = 0; i < tab.length; i+=2) { Object k = tab[i]; if (k != null && !containsMapping(k, tab[i + 1])) return false; } return true; } else if (o instanceof Map) { Map m = (Map)o; return entrySet().equals(m.entrySet()); } else { return false; // o is not a Map } } /** * Returns the hash code value for this map. The hash code of a map * is defined to be the sum of the hashcode of each entry in the map's * entrySet view. This ensures that <tt>t1.equals(t2)</tt> implies * that <tt>t1.hashCode()==t2.hashCode()</tt> for any two * <tt>IdentityHashMap</tt> instances <tt>t1</tt> and <tt>t2</tt>, as * required by the general contract of {@link Object#hashCode()}. * * <p><b>Owing to the reference-equality-based semantics of the * <tt>Map.Entry</tt> instances in the set returned by this map's * <tt>entrySet</tt> method, it is possible that the contractual * requirement of <tt>Object.hashCode</tt> mentioned in the previous * paragraph will be violated if one of the two objects being compared is * an <tt>IdentityHashMap</tt> instance and the other is a normal map.</b> * * @return the hash code value for this map. * @see Object#hashCode() * @see Object#equals(Object) * @see #equals(Object) */ public int hashCode() { int result = 0; Object[] tab = table; for (int i = 0; i < tab.length; i +=2) { Object key = tab[i]; if (key != null) { Object k = unmaskNull(key); result += System.identityHashCode(k) ^ System.identityHashCode(tab[i + 1]); } } return result; } /** * Returns a shallow copy of this identity hash map: the keys and values * themselves are not cloned. * * @return a shallow copy of this map. */ public Object clone() { try { IdentityHashMap t = (IdentityHashMap)super.clone(); t.entrySet = null; t.table = (Object[])(table.clone()); return t; } catch (CloneNotSupportedException e) { throw new InternalError(); } } private abstract class IdentityHashMapIterator implements Iterator { int index = (size != 0 ? 0 : table.length); // current slot. int expectedModCount = modCount; // to support fast-fail int lastReturnedIndex = -1; // to allow remove() boolean indexValid; // To avoid unecessary next computation Object[] traversalTable = table; // reference to main table or copy public boolean hasNext() { Object[] tab = traversalTable; for (int i = index; i < tab.length; i+=2) { Object key = tab[i]; if (key != null) { index = i; return indexValid = true; } } index = tab.length; return false; } protected int nextIndex() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); if (!indexValid && !hasNext()) throw new NoSuchElementException(); indexValid = false; lastReturnedIndex = index; index += 2; return lastReturnedIndex; } public void remove() { if (lastReturnedIndex == -1) throw new IllegalStateException(); if (modCount != expectedModCount) throw new ConcurrentModificationException(); expectedModCount = ++modCount; int deletedSlot = lastReturnedIndex; lastReturnedIndex = -1; size--; // back up index to revisit new contents after deletion index = deletedSlot; indexValid = false; // Removal code proceeds as in closeDeletion except that // it must catch the rare case where an element already // seen is swapped into a vacant slot that will be later // traversed by this iterator. We cannot allow future // next() calls to return it again. The likelihood of // this occurring under 2/3 load factor is very slim, but // when it does happen, we must make a copy of the rest of // the table to use for the rest of the traversal. Since // this can only happen when we are near the end of the table, // even in these rare cases, this is not very expensive in // time or space. Object[] tab = traversalTable; int len = tab.length; int d = deletedSlot; Object key = tab[d]; tab[d] = null; // vacate the slot tab[d + 1] = null; // If traversing a copy, remove in real table. // We can skip gap-closure on copy. if (tab != IdentityHashMap.this.table) { IdentityHashMap.this.remove(key); expectedModCount = modCount; return; } Object item; for (int i = nextKeyIndex(d, len); (item = tab[i]) != null; i = nextKeyIndex(i, len)) { int r = hash(item, len); // See closeDeletion for explanation of this conditional if ((i < r && (r <= d || d <= i)) || (r <= d && d <= i)) { // If we are about to swap an already-seen element // into a slot that may later be returned by next(), // then clone the rest of table for use in future // next() calls. It is OK that our copy will have
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?