WeakHashMap示例

22

我创建了一个 WeakHashMap,代码如下:

WeakHashMap<Employee,String> map = new WeakHashMap<Employee,String>();
map.put(emp,"hello");

如果emp是一个Employee对象。现在,如果我将emp设置为null或不再引用emp对象,那么WeakHashMap中的条目是否会被删除,即Map的大小是否为零?
而在HashMap的情况下是否反之亦然?
我的WeakHashMap理解正确吗?

6个回答

42

一个非常简单的例子,来说明已经说过的内容:

import java.util.WeakHashMap;

public class WeakHashMapDemo {

    public static void main(String[] args) {
        // -- Fill a weak hash map with one entry
        WeakHashMap<Data, String> map = new WeakHashMap<Data, String>();
        Data someDataObject = new Data("foo");
        map.put(someDataObject, someDataObject.value);
        System.out.println("map contains someDataObject ? " + map.containsKey(someDataObject));

        // -- now make someDataObject elligible for garbage collection...
        someDataObject = null;

        for (int i = 0; i < 10000; i++) {
            if (map.size() != 0) {
                System.out.println("At iteration " + i + " the map still holds the reference on someDataObject");
            } else {
                System.out.println("somDataObject has finally been garbage collected at iteration " + i + ", hence the map is now empty");
                break;
            }
        }
    }

    static class Data {
        String value;
        Data(String value) {
            this.value = value;
        }
    }
}

输出:

    map contains someDataObject ? true
    ...
    At iteration 6216 the map still holds the reference on someDataObject
    At iteration 6217 the map still holds the reference on someDataObject
    At iteration 6218 the map still holds the reference on someDataObject
    somDataObject has finally been garbage collected at iteration 6219, hence the map is now empty

对我来说花了很长时间!不得不改变程序 :) "在第708693次迭代中,somDataObject终于被垃圾回收了,因此地图现在为空" - Dmitry Minkovsky
@Yanflea,我曾经苦恼过弱引用在实际引用被垃圾回收时会发生什么。你的例子非常清晰地说明了弱引用将自身从映射中删除。非常感谢。 - tmj

15

我运行了示例代码,以了解HashMapWeakHashMap之间的区别。

            Map hashMap= new HashMap();
            Map weakHashMap = new WeakHashMap();

            String keyHashMap = new String("keyHashMap");
            String keyWeakHashMap = new String("keyWeakHashMap");

            hashMap.put(keyHashMap, "helloHash");
            weakHashMap.put(keyWeakHashMap, "helloWeakHash");
            System.out.println("Before: hash map value:"+hashMap.get("keyHashMap")+" and weak hash map value:"+weakHashMap.get("keyWeakHashMap"));

            keyHashMap = null;
            keyWeakHashMap = null;

            System.gc();  

            System.out.println("After: hash map value:"+hashMap.get("keyHashMap")+" and weak hash map value:"+weakHashMap.get("keyWeakHashMap"));

输出结果将为:

Before: hash map value:helloHash and weak hash map value:helloWeakHash
After: hash map value:helloHash and weak hash map value:null

6
如果`emp`是最后一个包含Employee 强可达引用的对象,则该地图中的条目可能被删除。Java文档总结得很好:“基于哈希表的使用弱键的Map实现。当其键不再处于常规使用中时,WeakHashMap中的条目将自动被删除。更准确地说,对于给定键的映射的存在不会阻止垃圾收集器丢弃该键[...]。当键已被丢弃时,它的条目从该地图中有效地删除,因此该类的行为与其他Map实现略有不同。”

 

那么在HashMap的情况下会反过来吗?

从WeakHashMap中删除条目不会影响程序中的任何其他引用。


是的,WeakHashMap 包含对对象的弱引用。弱引用在垃圾回收器发现它(和其他弱引用)是对象的最后一个剩余引用时,其指针会被“清除”。但这只会在某些 GC 循环中发生。我不确定在此情况下映射计数会发生什么变化。 - Hot Licks
@aioobe "如果emp包含了最后一个使得Employee强可达的引用,那么映射中的条目可能会被删除。" 我没明白。您能否详细解释一下? - Anand
@anand,如果emp是唯一一个引用某个Employee的变量(除了哈希映射中的其他弱引用),那么执行emp = null将使该员工符合垃圾回收的条件。请阅读可达性相关文档。 - aioobe

2

WeakHashMap示例:

Map map = new WeakHashMap();
Foo foo =  new Foo();
map.put(foo, "bar");
foo=null; // strong refrence is removed and object is available for garbage collection.  

HashMap示例:

Map map = new HashMap();
Foo foo =  new Foo();
map.put(foo, "bar");
foo=null; // even though the reference is nullified object will not garbage collected because map is having Strong refrence.

1
在其他的 Map 实现中,比如 HashMap 中,键是强引用的。例如,如果一个 HashMap 的键是如下所示的 Person 类,并且如果 Person 对象被设置为 null,即使在此之后我们执行 map.get(Person),我们仍然可以从内存中获取值,因为在 HashMap 中键是强引用的。
wm.put(person, person.getFirstName());
person = null;
System.gc();
System.out.println("Hash Map :" + wm.toString());

输出:哈希映射:{test.Person@12dacd1=John}

与HashMap相比,WeakHashMap是一种会在键没有内存引用时立即删除其条目的映射。例如,如果一个WeakHashMap的键如下所示为Person类,并且如果Person对象设置为null,则现在如果您执行map.get(Person),我们将得到null,因为该键没有引用(或者说是弱可达的)。

wm.put(person, person.getFirstName());
person = null;
System.gc();
System.out.println("Weak Hash Map :" + wm.toString());

输出:弱哈希映射:{}

1

Java中的引用是指向内存中创建对象的内存地址。在WeakHashMap中,使用了弱引用的概念。

一旦你在Java中创建一个对象并将其分配给某个变量,则它就变得强引用了。

弱引用对象可以类比于没有内存引用的对象,即它现在可以被垃圾回收器回收。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接