12

在下面的代码示例中,当键设置为 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;
}

}

Output: Weak Hash Map :{}

WeakHashMap与 一起使用HashMap并且键设置为空时,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;
}

}

输出: Weak Hash Map :{Java=Java, Hello=Hello, World=World, Programming=Programming} Hash Map :{Programming=Programming, World=World, Java=Java, Hello=Hello}

我的问题是为什么即使在丢弃密钥之后,第二个代码示例中的条目也不会WeakHashMap丢失?

4

6 回答 6

20

WeakHashMap当密钥不再可以从实时代码强烈访问时,A会丢弃条目。由于HashMap维护了对密钥的硬引用,因此密钥仍然可以访问并且WeakHashMap不会丢弃条目。

关键是该行为与对键对象的引用有关,而不是与可能曾经引用过键的任何变量的值有关。

于 2013-09-23T17:20:01.317 回答
4

必须在其他任何地方丢弃一个对象,然后 WeakHashMap 清除该对象。像 WeakReference 一样,它的目的是记住一个仍在使用的对象。不会导致永远持有对象的内存泄漏。

在您的示例设置hm = null;中可以看到 WeakHashMap 清理的神奇之处。

于 2013-09-23T17:18:39.943 回答
3

您已经设置null了指针,k1,k2,k3,k4但仍然包含对那些. 并且因为包含引用,所以 GC 不会删除 Keys 的实际实例。仍然打印所有这些。HashMapWeakHashMapKeysHashMapWeakHashMap

尝试仅使用HashMap-> 运行此示例,即使您已取消这些引用HashMap仍将保留它们。

于 2013-09-23T17:22:49.270 回答
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"); 
} 

}
于 2019-01-30T06:18:59.443 回答
0

HashMap 支配 gc(垃圾收集器)。

gc 支配着 WeakHashMap。

即使我们在 k1,k2,k3,k4 上设置了 null,gc 也不会从 HashMap 中删除,因为 gc 会将它们全部删除并为 WeakHashMap 提供空映射,因此名称为 WeakHashMap

于 2014-08-21T06:54:06.160 回答
0

当 JVM 运行垃圾收集器并发现一个没有引用变量的对象时,它将销毁它,但是当该对象充当 HashMap 中的键时,垃圾收集器不会销毁它。在 WeakHashmap 的情况下,如果它没有引用,即使它充当键,它也会破坏对象。在上面的代码中甚至 k1,k2,k3,k4=null

但是因为这些对象是 hashmap 中的关键,所以它们不会被垃圾收集破坏。如果你想销毁它,只需通过设置 hm=null 将它们从 Hashmap 中删除;然后 System.gc(); 将摧毁 k1,k2,k3,k4

于 2020-06-24T18:59:49.570 回答