WeakHashMap的用法?

时间:2013-12-23 11:50:59

标签: java hashmap weakhashmap

WeakHashMap是Map接口的一个实现,Grabage Collector可以回收值对象的内存 如果相应的密钥不再被任何程序部分引用。因此,如果密钥不再用于程序中。它的进入 对象将被垃圾收集,无论其使用情况如何。它清晰到这里

这与HashMap不同,即使不再引用key,值对象仍保留在HashMap中。我们需要明确地打电话  HashMap对象上的remove()方法删除值。调用remove将只删除map中的条目。它对GC的准备就绪了  取决于它是否仍然在程序中的某个地方使用。

Please find this coding example explaining above

根据我的理解,在HashMap上使用WeakHashMap

我的理解是,只有当我们想要确保Grabage Collector回收值对象时,才应该使用WeakHashMap  密钥不再由任何程序部分引用。这使程序内存有效我的理解是正确的吗?

根据JavaDocs使用WeakHashMap,我可以发现此声明

  

此类主要用于等于的关键对象   方法使用==运算符测试对象标识。

我没有得到上述声明的含义以及它与我对WeakHashMap用法的理解形成鲜明对比。实际上我没有得到这个陈述与WeakHashMap的使用有什么关系?

更新: - 进一步仔细阅读以下声明javadocs

  

WeakHashMap中的条目将在其键时自动删除   不再是一般用途。更准确地说,存在一个   给定密钥的映射不会阻止密钥被丢弃   由垃圾收集器,即,最终确定,最终确定,和   然后回收。当一个密钥被丢弃时,它的输入是有效的   从地图中删除,所以这个类的行为有点不同   其他Map实现。

我为了我和他人的利益而修改我的理解

根据我的修订理解,将WeakHashMap用于HashMap

我们应该只在我们想要确保在GC运行时从地图中删除键值对时才能使用WeakHashMap,而键不再是普通用途而不是地图本身。

例如: -

    WeakHashMap<Integer, String> numbers = new WeakHashMap<Integer, String>();
    numbers.put(new Integer(1), "one");// key only used within map not anywhere else
    numbers.put(new Integer(2), "two");
    System.out.println(numbers.get(new Integer(1))); // prints "one"
    System.gc();
    // let's say a garbage collection happens here
    System.out.println(numbers.get(new Integer(1))); // prints "null"
    System.out.println(numbers.get(new Integer(2))); // prints "null"


    Object key = new Object();
    m1.put(key, c1);
    System.out.println(m1.size());
    key = null or new Object() ; // privious key only used within map not anywhere else
    System.gc();
    Thread.sleep(100);
    System.out.println(m1.size());

5 个答案:

答案 0 :(得分:2)

这是因为当对象不再具有来自程序的任何其他部分的强引用时,对象将被垃圾收集(GCed)。

给定WeakHashMap<MyObject, String>然后我们执行以下操作:

MyObject mo = new MyObject();
map.put(mo, "Test");
mo = null;

然后条目mo -> Test将有资格获得GC。这意味着如果您有一个自定义.equals实现使用MyObject的某些属性来测试相等性,那么以后就不能这样做了:

MyObject mo2 = new MyObject();
map.get(mo2);

因为即使您重写的.equals方法可能会说mo2.equals(mo) == true,但mo2 == mo并非如此,因此该条目可能已经过GC。

关键在于,如果您保留对mo的引用并使用该引用从Map检索值,那么该引用必须== mo,因此有两件事情是的:

  1. 条目mo -> Test无法加入
  2. 您可以使用基于==的{​​{1}}方法从地图中检索条目
  3. 基本上;由于GC将使用强引用来测试对象是否可以进行GC操作,因此最好确保您的.equals方法执行相同操作以避免混淆。

答案 1 :(得分:1)

文档意味着此代码不是很有用:

WeakHashMap<Integer, String> numbers = new WeakHashMap<Integer, String>();
numbers.put(new Integer(1), "one");
numbers.put(new Integer(2), "two");
System.out.println(numbers.get(new Integer(1))); // prints "one"
// let's say a garbage collection happens here
System.out.println(numbers.get(new Integer(1))); // prints "null"
System.out.println(numbers.get(new Integer(2))); // prints "null"

对于任何不同实例可以相等的类,都会发生这种情况。 javadoc只是警告你,如果你没有注意到,这是没有用的。

答案 2 :(得分:1)

运行此测试

    Object key = new Object();
    WeakHashMap m = new WeakHashMap();
    m.put(key, 1);
    System.out.println(m.size());
    key = null;
    System.gc();
    Thread.sleep(100);
    System.out.println(m.size());

虽然System.gc不保证运行GC但是在我的Oracle JVM 7上它始终运行并打印此测试

1
0

这意味着GC从地图中删除了该条目,因为除了地图本身

之外,没有从任何地方引用该键

答案 3 :(得分:0)

我认为这意味着相等的对象测试是在内存中使用对象位置,而不仅仅是因为两个不同的实例在其值中恰好相等。

如果不是这种情况,则很难判断该键是否被引用了更多且不同但是“相等”的值,实例可能会被引用并用于查找该值。

如果它说密钥必须具有引用相等性,那么你可能会更清楚,这样你就知道什么时候密钥不再被WeakHashMap实例的其他任何东西引用

答案 4 :(得分:0)

在Evgeniy Dorofeev回答的基础上,这是一个带有一些问题的例子:

import java.util.Map;
import java.util.WeakHashMap;

public class WeakHashMapTest {

    public static void main(String[] args) throws InterruptedException {
        String key = new String();
        Map<String, String> m = new WeakHashMap();

        m.put(key, "value");
        System.out.println(m.size());

        m.put("key", "value");
        System.out.println(m.size());

        m.put(new String(), "value");
        System.out.println(m.size());

        m.put(new String("k"), "value");
        System.out.println(m.size());

        key = null;
        System.gc();
        Thread.sleep(100);

        System.out.println(m.size());
    }
}

输出

1
2
2
3
1