HashMap - 更改键值

HashMap - Changing key value

HashMap<StringBuilder, StringBuilder> aMap = new 
       HashMap<StringBuilder, StringBuilder>();

StringBuilder emp = new StringBuilder("Stack");
StringBuilder val = new StringBuilder("Programmer");

aMap.put(emp, val);
emp = new StringBuilder("sss");
System.out.println(aMap);`

虽然 emp 值被改变了,但它没有反映在 HashMap 中。是因为 HashMap 在放入新值时使用了某种复制构造函数吗?

现在使用 Wea​​kHashMap:

WeakHashMap<StringBuilder, StringBuilder> aMap1 = 
            new WeakHashMap<StringBuilder, StringBuilder>();
    StringBuilder emp1 = new StringBuilder("WeakStack");
    StringBuilder val1 = new StringBuilder("Programmer");
aMap1.put(emp1, val1);
emp1 = new StringBuilder("WeakStack1");

经过一些 GC 调用后,aMap1 变空了。为什么这样?是因为指向的键不存在了吗?

更新:我从答案中了解到键是从 HashMap 引用的,因此当上面 HashMap 中的 emp(可变键)通过向其附加字符串来更改时,例如 emp.append("changed"),反映在HashMapWeakHashMap 也是如此(如果可变键是 changed/updated,则反映更改)。这意味着该键是从 WeakHashMap 引用的。

任何人都可以解释一下 WeakHashMap 实施方式的不同之处在于,虽然密钥被引用但可以被垃圾收集?

谢谢。

emp = new StringBuilder("sss"); 不会影响 HashMap 中已有的条目(由语句 new StringBuilder("Stack"); 创建的条目),因为 HashMap 包含自己的引用到最初由 emp 引用的 StringBuilder 实例。它不会创建 StringBuilder 实例的副本,它只会保留引用的副本。

另一方面,对于 WeakHashMapWeakHashMap 中存在一个键并不能阻止它被垃圾回收,所以如果没有其他引用该键,你放入地图,GC 可以释放该实例。因此,当你为emp1分配一个新实例后,只有map包含了对它引用的原始实例的引用,GC才能释放它。

这是相关的 Javadoc 参考资料:

An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. More precisely, the presence of a mapping for a given key will not prevent the key from being discarded by the garbage collector

编辑:

至于WeakHashMap的实现有何不同,WeakHashMapEntry扩展了WeakReference<Object>,是一个实例引用另一个实例(在这种情况下是条目的键)并且不会阻止 GC 释放其所指对象。