IdentityHashMap
程序员文章站
2022-04-06 13:05:36
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不存在两种,结合图形在看代码就很容易理解了。
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 标签的作用:
- 一般的 continue 会退回最内层循环的开头(顶部),并继续执行。
- 带标签的 continue 会到达标签的位置,并重新进入紧接在那个标签后面的循环。
- 一般的 break 会中断并跳出当前循环。
- 带标签的 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); } }
下一篇: 每日一题283. 移动零