WeakHashMap与HashMap的区别

13
在以下代码示例中,当键设置为null并调用System.gc()时,WeakHashMap将失去所有映射并被清空。
class WeakHashMapExample {

public static void main(String[] args) {

    Key k1 = new Key("Hello");
    Key k2 = new Key("World");
    Key k3 = new Key("Java");
    Key k4 = new Key("Programming");

    Map<Key, String> wm = new WeakHashMap<Key, String>();


    wm.put(k1, "Hello");
    wm.put(k2, "World");
    wm.put(k3, "Java");
    wm.put(k4, "Programming");
    k1=null;
    k2=null;
    k3=null;
    k4=null;
    System.gc();
    System.out.println("Weak Hash Map :"+wm.toString());

}

}

class Key{

private String key;

public Key(String key) {
    this.key=key;
}

@Override
public boolean equals(Object obj) {
    return this.key.equals((String)obj);
}
@Override
public int hashCode() {
    return key.hashCode();
}
@Override
public String toString() {
    return key;
}

}

输出:弱哈希映射:{}

当使用WeakHashMapHashMap一起使用并将键设置为null时,WeakHashMap不会失去其键值映射。

class WeakHashMapExample {

public static void main(String[] args) {

    Key k1 = new Key("Hello");
    Key k2 = new Key("World");
    Key k3 = new Key("Java");
    Key k4 = new Key("Programming");

    Map<Key, String> wm = new WeakHashMap<Key, String>();
    Map<Key, String> hm=new HashMap<Key, String>();

    wm.put(k1, "Hello");
    wm.put(k2, "World");
    wm.put(k3, "Java");
    wm.put(k4, "Programming");

    hm.put(k1, "Hello");
    hm.put(k2, "World");
    hm.put(k3, "Java");
    hm.put(k4, "Programming");
    k1=null;
    k2=null;
    k3=null;
    k4=null;
    System.gc();
    System.out.println("Weak Hash Map :"+wm.toString());
    System.out.println("Hash Map :"+hm.toString());
}

}

class Key{

private String key;

public Key(String key) {
    this.key=key;
}

@Override
public boolean equals(Object obj) {
    return this.key.equals((String)obj);
}
@Override
public int hashCode() {
    return key.hashCode();
}
@Override
public String toString() {
    return key;
}

}

输出: 弱哈希映射:{Java=Java,Hello=Hello,World=World,Programming=Programming} 哈希映射:{Programming=Programming,World=World,Java=Java,Hello=Hello}

我的问题是为什么在第二个代码示例中键被丢弃后WeakHashMap没有失去其条目?

6个回答

20
一个 WeakHashMap 会在key不再从活动代码中强烈引用时丢弃该项。由于HashMap 维护对键的硬引用,因此这些键仍然可达,所以WeakHashMap 不会丢弃这些条目。
重点在于行为涉及与键对象的引用,而不是曾经可能具有对键的引用的任何变量的值。

我从未想过变量只是包含指针,这很有启发性,谢谢! - xorinzor

4
在其他地方必须丢弃对象,然后WeakHashMap清除该对象。与WeakReference类似,它的目的是在对象仍在使用时记住它。而不会导致永远持有对象从而造成内存泄漏。
在您的示例中设置hm = null;以看到WeakHashMap清理工作的神奇效果。

是的,在 System.gc() 之前设置 hm=null 可以清除 WHM。谢谢,我明白了。 - Nishant

3
您将 k1,k2,k3,k4 指针设为null,但是HashMapWeakHashMap仍然包含这些Key的引用。由于HashMap包含引用,因此GC不会删除Keys的实例。 WeakHashMap仍然打印所有键。尝试仅使用HashMap运行此示例 - 即使您已将这些引用设置为nullHashMap仍将保留它们。

1
尝试这个 -
class WeakHashMapExample {

public static void main(String[] args) {

    Key k1 = new Key("Hello");
    Key k2 = new Key("World");
    Key k3 = new Key("Java");
    Key k4 = new Key("Programming");

    Map<Key, String> hm=new HashMap<Key, String>();   
    hm.put(k1, "Hello");
    hm.put(k2, "World");
    hm.put(k3, "Java");
    hm.put(k4, "Programming");
    k1=null;
    k2=null;
    k3=null;
    k4=null;
    System.gc();
    System.out.println("Hash Map :"+hm);

    System.out.println("Same thing with weakHash Map - "); 

    k1 = new Key("Hello");
    k2 = new Key("World");
    k3 = new Key("Java");
    k4 = new Key("Programming");

    Map<Key, String> wm = new WeakHashMap<Key, String>();

    wm.put(k1, "Hello");
    wm.put(k2, "World");
    wm.put(k3, "Java");
    wm.put(k4, "Programming");
    k1=null;
    k2=null;
    k3=null;
    k4=null;
    System.gc();
    System.out.println("Weak Hash Map :"+wm);
}

}

class Key{

private String key;

public Key(String key) {
    this.key=key;
}

@Override
public boolean equals(Object obj) {
    return this.key.equals((String)obj);
}
@Override
public int hashCode() {
    return key.hashCode();
}
@Override
public String toString() {
    return key;
}

public void finalize() 
{ 
   System.out.println("Finalize method is called"); 
} 

}

0

HashMap 主宰了垃圾回收机制。

垃圾回收机制主宰了 WeakHashMap。

即使我们在 k1、k2、k3、k4 上设置了 null,垃圾回收机制不会从 HashMap 中删除它们,而是将它们全部删除并为 WeakHashMap 提供空映射,因此称为 WeakHashMap。


0

当JVM运行垃圾收集器并发现一个没有引用变量的对象时,它将销毁该对象,但是如果该对象充当HashMap中的键,则垃圾收集器不会销毁它。在WeakHashmap的情况下,即使它充当键而没有引用,它也会被销毁。在上面的代码中,即使k1、k2、k3、k4为null,但由于这些对象是HashMap中的键,它们不会被垃圾回收。

如果您想要销毁它们,只需从HashMap中删除它们,方法是将hm=null;然后使用System.gc();将销毁k1、k2、k3、k4。


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