java - 以 Map 作为键的 WeakHashMap 在修改键后返回空值的意外行为

标签 java hashmap hashcode

我们需要缓存有关某些对象的一些信息,因此我们使用 java.util.WeakHashMap。如果我们的键是 java.util.HashMap,我们会看到意外的行为。

例子:

WeakHashMap<Object, Object> whm = new WeakHashMap<>();
Map<String, String> map = new HashMap<>();
whm.put(map, "map");
System.out.println(map + ": " + whm.get(map) + " " + whm + " " + whm.containsKey(map));

map.put("key", "value");
System.out.println(map + ": " + whm.get(map) + " " + whm + " " + whm.containsKey(map));
System.out.println(map.hashCode());
System.out.println(whm.entrySet().stream().map(e -> e.getKey().hashCode()).collect(Collectors.toList()));
System.out.println(whm.entrySet().stream().map(e -> e.getKey() == map).collect(Collectors.toList()));

输出是:

{}: map {{}=map} true
{key=value}: null {{key=value}=map} false
112004910
[112004910]
[true]

为什么 whm.get(map) null 在调用 whm.put(map, "map") 之后?

java.util.HashSet 的相同结果...

对于 AtomicInteger 它按预期工作:

WeakHashMap<Object, Object> whm = new WeakHashMap<>();
AtomicInteger integer = new AtomicInteger(0);
whm.put(integer, "integer");
System.out.println(integer + ": " + whm.get(integer) + " " + whm + " " + whm.containsKey(integer));

integer.set(1);
System.out.println(integer + ": " + whm.get(integer) + " " + whm + " " + whm.containsKey(integer));

结果:

0: integer {0=integer} true
1: integer {1=integer} true

最佳答案

这与它是一个 map 无关,而与您修改 map 键有关,这基本上是您应该避免做的事情。通过向 map 添加条目,您正在更改其哈希码。这很容易证明:

import java.util.HashMap;
import java.util.Map;

public class Test {

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        System.out.println(map.hashCode());
        map.put("key", "value");
        System.out.println(map.hashCode());        
    }
}

此时尝试获取条目将失败,因为它的散列码不再与插入它的散列码匹配。

AtomicInteger 不会覆盖 equalshashCode,因此您获得的是对象标识相等性 - 它的哈希码在以下情况下不会更改你调用 set

关于java - 以 Map 作为键的 WeakHashMap 在修改键后返回空值的意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46443917/

相关文章:

C#:在键是对象的地方使用 ContainsKey

c# - Dictionary 是否损坏或 GetHashCode() 应该仅基于不可变成员?

java - 如何对自定义 RecordReader 和 InputFormat 类进行单元测试?

java - 绘制 Jpanel 的边框而不调整内容大小 (Java)

java - 获取主页的实时库存数据

java - TableColumn #setCellValueFactory 对于具有 HashMap 的类

java - 替换 hashmap java 中的重复值字符串

java - 在 Hashmap<Arraylist,Arraylist> 中找到最大值的最佳方法

java - 根据环境定义不同的log4j2.xml配置

java - java中具有相同哈希码的对象排序