欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

IdentityHashMap

程序员文章站 2022-07-09 12:47:10
ApplicationShutdownHooks中使用到了IdentityHashMap,查看其api解释为 大致意思为IdentityHashMap中key是否相等的规则判断是根据key的引用是否相等来判断,而不像正常的HashMap是通过key的值是否相等来判断。 equals方法 Identi ......

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不存在两种,结合图形在看代码就很容易理解了。

IdentityHashMap

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);
        }
    }