在下面的代码示例中,当键设置为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
一起使用且密钥设置为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
在第二个代码示例中丢失了条目,即使在丢弃密钥之后呢?
答案 0 :(得分:16)
当密码不再可从实时代码中轻松访问时,WeakHashMap
会丢弃条目。由于HashMap
维护对密钥的硬引用,因此密钥仍可访问,WeakHashMap
不会丢弃条目。
关键在于行为与对关键对象的引用有关,而不是与曾经可能具有对键的引用的任何变量的值有关。
答案 1 :(得分:3)
必须在其他地方丢弃对象,然后WeakHashMap清除该对象。与WeakReference一样,它的目的是记住一个对象,如果它仍在使用中。永远不会导致内存泄漏持有对象。
在您的示例中设置hm = null;
以查看WeakHashMap清理的魔力。
答案 2 :(得分:3)
您已在指针null
上设置k1,k2,k3,k4
,但HashMap
和WeakHashMap
仍包含对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