美文网首页
04_IdentityHashMap

04_IdentityHashMap

作者: 0x70e8 | 来源:发表于2018-03-22 20:46 被阅读0次

    IdentityHashMap是一个特殊的HashMap,它允许非引用相等的key,即使他们equals结果是true。
    和HashMap HashTable不同的是,它是简单的对象数组结果,一个map对象占两个数组slot,一个放key一个放value,十分简单粗暴。
    先看无参构造器:

     /**
         * Constructs a new, empty identity hash map with a default expected
         * maximum size (21).
         */
        public IdentityHashMap() {
            init(DEFAULT_CAPACITY);
        }
    
        private void init(int initCapacity) {
            // assert (initCapacity & -initCapacity) == initCapacity; // power of 2
            // assert initCapacity >= MINIMUM_CAPACITY;
            // assert initCapacity <= MAXIMUM_CAPACITY;
    
            threshold = (initCapacity * 2)/3;
            table = new Object[2 * initCapacity];
        }
    

    看一下key相等性的判断:
    put方法():

    public V put(K key, V value) {
            Object k = maskNull(key);
            Object[] tab = table;
            int len = tab.length;
            // index也是通过hash算法来寻址的。
            int i = hash(k, len);
    
            Object item;
            while ( (item = tab[i]) != null) {
                // 注意这里的key相等性判断是用 == ,不是equals 只有是同一个对象才能算是重复的key
                if (item == k) {
                    @SuppressWarnings("unchecked")
                        V oldValue = (V) tab[i + 1];
                    tab[i + 1] = value;
                    return oldValue;
                }
                i = nextKeyIndex(i, len);
            }
    
            modCount++;
    
            // 这里就可以明显看出,一个slot存key,后续一个存value。
            tab[i] = k;
            tab[i + 1] = value;
            if (++size >= threshold)
                resize(len); // len == 2 * current capacity.
            return null;
        }
    

    IdentityHashMap的核心实现似乎在于hash算法,它负责添加和查询时的寻址。

        /**
         * Returns index for Object x.
         */
        private static int hash(Object x, int length) {
            int h = System.identityHashCode(x);
            // Multiply by -127, and left-shift to use least bit as part of hash
            return ((h << 1) - (h << 8)) & (length - 1);
        }
    

    它的迭代封装,把key和value封装到Entry对象中:

    private abstract class IdentityHashMapIterator<T> implements Iterator<T> {
            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 unnecessary next computation
            Object[] traversalTable = table; // reference to main table or copy
    
            public boolean hasNext() {
                Object[] tab = traversalTable;
                // i+=2
                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;
                // 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;
                }
    
                size--;
    
                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
                        // a gap in the "wrong" place, since it will never
                        // be used for searching anyway.
    
                        if (i < deletedSlot && d >= deletedSlot &&
                            traversalTable == IdentityHashMap.this.table) {
                            int remaining = len - deletedSlot;
                            Object[] newTable = new Object[remaining];
                            System.arraycopy(tab, deletedSlot,
                                             newTable, 0, remaining);
                            traversalTable = newTable;
                            index = 0;
                        }
    
                        tab[d] = item;
                        tab[d + 1] = tab[i + 1];
                        tab[i] = null;
                        tab[i + 1] = null;
                        d = i;
                    }
                }
            }
        }
    
        private class EntryIterator extends IdentityHashMapIterator<Map.Entry<K,V>>{
            private Entry lastReturnedEntry = null;
    
            public Map.Entry<K,V> next() {
                // 私有内部类Entry
                lastReturnedEntry = new Entry(nextIndex());
                return lastReturnedEntry;
            }
            // ...
            private class Entry implements Map.Entry<K,V> {
                private int index;
    
                private Entry(int index) {
                    this.index = index;
                }
                // ...
            }
    
        }
    

    相关文章

      网友评论

          本文标题:04_IdentityHashMap

          本文链接:https://www.haomeiwen.com/subject/bfszqftx.html