IdentityHashMap

2018-10-14 10:49:28来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

ApplicationShutdownHooks中使用到了IdentityHashMap,查看其api解释为

This class implements the Map interface with a hash table, using reference-equality in place of object-equality when comparing keys (and values). In other words, in an IdentityHashMap, two keys k1 and k2 are considered equal if and only if (k1==k2). (In normal Map implementations (like HashMap) two keys k1 and k2 are considered equal if and only if (k1==null ? k2==null : k1.equals(k2)).)

大致意思为IdentityHashMap中key是否相等的规则判断是根据key的引用是否相等来判断,而不像正常的HashMap是通过key的值是否相等来判断。

equals方法

IdentityHashMap中的equals方法是首先对比两个map的引用是否相等,如果不相等,再去循环所有的值判断是否相等,判断值是否相等时,使用的判断公式为 == 

public boolean equals(Object o) {
        // 引用相等直接返回true
        if (o == this) {
            return true;
        } else if (o instanceof IdentityHashMap) {
            // 长度或内容有一个不相等时,返回false,否则返回true
            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];
                // contanisMapping方法为判断当前Map的key为k的值是否等于传入Map的key为k的值
                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
        }
    }

private boolean containsMapping(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)
            //  判断是否相等时使用==,为判断两个对象的引用是否相等
                return tab[i + 1] == value;
            if (item == null)
            // 未找到该key,返回false
                return false;
            i = nextKeyIndex(i, len);
        }
    }

 

 

put方法

put方法是如何操作底层数组的,下图给予了说明,分为key存在和key不存在两种,结合图形在看代码就很容易理解了。

put方法说明

public V put(K key, V value) {
        final Object k = maskNull(key);

        retryAfterResize: for (;;) {
            final Object[] tab = table;
            final int len = tab.length;
            int i = hash(k, len);
            // 如果key存在,就将新的value给之前value所在的位置
            // key如果在table[i] value就在table[i+1],所以nextKeyIndex的作用就是i+2
            for (Object item; (item = tab[i]) != null;
                 i = nextKeyIndex(i, len)) {
                if (item == k) {
                    @SuppressWarnings("unchecked")
                        V oldValue = (V) tab[i + 1];
                    tab[i + 1] = value;
                    return oldValue;
                }
            }

            final int s = size + 1;
            // Use optimized form of 3 * s.
            // Next capacity is len, 2 * current capacity.
            // table空间不足时的扩容

            if (s + (s << 1) > len && resize(len))
                continue retryAfterResize;
            // 如果key不存在时的赋值
            modCount++;
            tab[i] = k;
            tab[i + 1] = value;
            size = s;
            return null;
        }
    }

 

在put方法段中有段代码为: retryAfterResize: for (;;) { ,然后下面接着有一段代码为continue retryAfterResize;  这是java标签的用法(但此处我不知道为什么要用java标签,直接continue不就行了)

java 标签的作用:

  1. 一般的 continue 会退回最内层循环的开头(顶部),并继续执行。
  2. 带标签的 continue 会到达标签的位置,并重新进入紧接在那个标签后面的循环。
  3. 一般的 break 会中断并跳出当前循环。
  4. 带标签的 break 会中断并跳出标签所指的循环。

标签测试:

public class Test {

    public static void main(String[] args) throws InterruptedException {
        label: for (int j = 0; j < 2; j++) {
            for (int i = 1; i < 10; i++) {
                Thread.sleep(1000);
                if (i % 3 == 0) {
                    System.out.println(i);
                    continue label;
                }
                System.out.println(j + " run");
            }
        }
    }
}
------------------
输出结果:

0 run

0 run

3

1 run

1 run

3

 

get方法

public V get(Object key) {
        Object k = maskNull(key);
        Object[] tab = table;
        int len = tab.length;
        int i = hash(k, len);
     // 死循环遍历table数组
        while (true) {
            Object item = tab[i];
       // 如果命中相同的key,就返回table[i+1]的值
            if (item == k)
                return (V) tab[i + 1];
       // 如果遍历完数组还未命中,就返回空
            if (item == null)
                return null;
            i = nextKeyIndex(i, len);
        }
    }

 

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:transient是干嘛的

下一篇:java中Future与FutureTask使用与分析