WeakHashMap vs HashMap
A WeakHashMap
discards entries when the key is no longer strongly reachable from live code. Since the HashMap
maintains a hard reference to the keys, the keys are still reachable and the WeakHashMap
doesn't discard the entries.
The point is that the behavior has to do with references to the key objects, not to the value of any variable that might have at one time had a reference to the keys.
An object must be discarded everywhere else, and then the WeakHashMap clears that object. Like a WeakReference its purpose is to remember an object if it is still in use. Without causing a memory leak forever holding an object.
In your example set hm = null;
to see the magic of the WeakHashMap cleaning up.
You have set null
on pointers k1,k2,k3,k4
but HashMap
and WeakHashMap
still contains references to those Keys
. And because HashMap
is containing reference, actual instances of Keys are not deleted by GC. WeakHashMap
still prints all of them.
Try run this example only with HashMap
-> even that you've nulled out those references HashMap
will still keep them.
Try this one -
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");
}
}