WeakHashMap vs HashMap

时间:2013-09-23 17:14:47

标签: java weakhashmap

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

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;
}

}

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

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

6 个答案:

答案 0 :(得分:16)

当密码不再可从实时代码中轻松访问时,WeakHashMap会丢弃条目。由于HashMap维护对密钥的硬引用,因此密钥仍可访问,WeakHashMap不会丢弃条目。

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

答案 1 :(得分:3)

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

在您的示例中设置hm = null;以查看WeakHashMap清理的魔力。

答案 2 :(得分:3)

您已在指针null上设置k1,k2,k3,k4,但HashMapWeakHashMap仍包含对Keys的引用。由于HashMap包含引用,因此GC不会删除实际的键实例。 WeakHashMap仍会打印所有这些内容。

尝试仅使用HashMap运行此示例 - &gt;即使您已经将这些参考文献排除在外HashMap仍将保留它们。

答案 3 :(得分:0)

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

gc支配WeakHashMap。

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

答案 4 :(得分:0)

尝试这个-

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"); 
} 

}

答案 5 :(得分:0)

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

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