0

我已经将一个对象作为键存储在WeakHashMap. 现在,如果我更改它的值,然后调用 GC 和 print map,那么什么都没有。

public static void main(String[] args) throws InterruptedException{

    WeakHashMap map = new WeakHashMap();
    Integer obj = new Integer(200);
    map.put(obj, "sgdjsgd");
    obj=new Integer(20);
    System.gc();
    Thread.sleep(2000);
    System.out.println(map);
}
  • 预期输出:{200,"sgdjsgd"}
  • 实际输出:{}
4

5 回答 5

1

WeakHashMap 可能表现得好像一个未知线程正在默默地删除条目。

WeakHashMap.Entry是一个对象,其WeakReference引用对象是key您传递给的对象map.put()。也就是说,如果key变为weakly reachable,垃圾收集器将自动声明它是可终结的。

Java SE 8 文档

一个对象是弱可达的,如果它既不是强可达也不是软可达,但可以通过遍历弱引用来达到。当对弱可达对象的弱引用被清除时,该对象就有资格进行终结。

在这行代码中

    Integer obj = new Integer(200);
    map.put(obj, "sgdjsgd");

theobj是对由创建的整数对象的强引用,new Integer(200)然后将它传递给map.put()创建 a WeakReference(假设它被称为w)来保存该整数对象。

但在这一行之后:

obj = new Integer(20);

obj指向另一个拥有 20 的整数对象(仍然w指向拥有 200 的整数对象)。但是更改obj指向的对象将使所指对象w变为weakly reachable,因为它只能通过遍历弱引用(即w)来到达。

当控制从方法调用返回到System.gc()时,JVM 已尽最大努力回收所有丢弃的对象。如上所述,垃圾收集器将自动声明弱可达对象可终结并最终清除它们。

所以w清除了,地图中的条目被垃圾收集器丢弃,结果,你的地图不包含任何内容。

于 2019-10-23T11:02:59.510 回答
1

user207421 说得非常准确:您的代码完全按照设计工作。我不清楚你是如何期待其他东西的,但我想指出:

  • 您的代码不会更改地图内的任何内容。分配一个新值 20obj只会更改该变量。地图中的关键仍然是Integer持有值 200。
  • 分配 20 toobj确保映射中没有对键 200 的其他引用,这就是允许垃圾收集器从映射中删除该键的原因。

如果您想更改地图中的键:永远不要。包括 a 在内的散列映射WeakHashMap按其散列码存储对象。更改密钥对象很可能会更改哈希码。所以地图将无法再次找到钥匙,即使它在那里。如果您需要此功能,您必须首先从地图中删除密钥,然后插入新密钥:

    String value = map.remove(obj);
    obj = Integer.valueOf(20);
    map.put(obj, value);

通过对您的代码进行此更改,我得到以下输出:

{20=sgdjsgd}

于 2019-10-23T12:07:45.213 回答
0
Integer obj = new Integer(200);

这会默认创建一个对 Integer 对象 obj 的强引用 ----strong reference ---->200

map.put(obj, "sgdjsgd");

obj ----弱引用 ----->200
现在整数对象 200 具有强引用和弱引用,因此它不符合 GC 条件

obj=new Integer(20);

obj ----强引用---->20

obj-----X----->200 obj ----弱引用--->200

在这里,现有的对 200 的强引用已经丢失。所以整数对象 200 只剩下弱引用,将被 GC 急切地收集。

正因为如此,key 也会从 weakHashMap 中删除

查看此链接了解更多详情 http://www.fis.unipr.it/lca/tutorial/java/refobjs/about/weak.html

于 2019-10-25T07:19:43.173 回答
0

我不确定您要做什么,但我在您的代码中看到的是,您将一个新对象分配给以前指向 WeakHashMap 中的键的引用,通过这样做,原始键(整数(200) ) 没有指针,所以它没用,因为你永远无法到达那个键,所以 gc 会处理它是合乎逻辑的

于 2019-10-23T10:03:42.693 回答
0

使用此代码,您正在更改存储在内存中的指针obj

obj=new Integer(20);

在这一行之前,obj持有一个指向new Integer(200);

现在,相反,在内存中保存一个与以前不同obj的指针引用。new Integer(20);

因此,因为WeakHashMap持有弱引用,当垃圾收集器运行时,它会收集映射所引用的对象,因此当您打印映射时它会显示{},因为不再找到保存在映射键中的指针。

于 2019-10-23T09:58:46.850 回答