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 + -
显示快捷键?