Behaviour of weakhashmap with String literal and String object

java, weakhashmap

Solution

Strings literals are interned, which basically means that there is a cache, mostly referred to as the String pool. So String literals are always strongly referenced - making them not suitable to use as keys in a weak structure e.g. `WeakReference` and `WeakHashMap`.

The same goes for autoboxed `int`s: also `Integer` keeps a cache of `Integer` objects for `int` values in the range [-128, 127]. So you should also not be using `int` for keys in a weak structures.

However, you can work around these problems by creating a new object when inserting an entry, e.g. in the following example, the "a" entry will eventually be removed from the map, but the "b" entry will stay in there forever which is infact a memory leak:

WeakHashMap<String, Object> map = new WeakHashMap<>();
map.add(new String("a"), new Object());
map.add("b", new Object());

The same example is valid for integers:

WeakHashMap<Integer, Object> map = new WeakHashMap<>();
map.add(new Integer(56), new Object());
map.add(57, new Object());

Here the entry for 57 will stay in there forever, because of `Integer`'s caching, but the 56 entry can be removed by the garbage collector.

Also `Boolean` has caching, but only for 2 values of course. Where `Integer` has 256 potentially dangerous values, `String` practically has unlimited occurences that can be dangerous - you only have to use literals (or use `String.intern()`) to create them. It might be that there exist other dangerous classes, too.

Problem

I am understanding the concept of WeakhashMap. String literal and String object made it difficult to understand. Following is the code: ``` package com.lnt.StringBuf; import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; public class Test1 { public static void main(String[] args) { Map w = new WeakHashMap(); Map h = new HashMap<>(); String hkey = new String("hashkey"); String wkey = new String("weakkey"); /* String hkey = "hashkey"; String wkey = "weakkey";*/ h.put(hkey, 1); w.put(wkey, 1); System.gc(); System.out.println("Before"); System.out.println("hashmap size: " + h.size()); System.out.println("weakmap size: " + w.size()); System.out.println("Hashmap value: " + h.get("hashkey") + "\t" + "weakmap value: " + w.get("weakkey")); hkey = null; wkey = null; System.gc(); System.out.println(hkey+" "+wkey); System.out.println("After"); System.out.println("hashmap size: " + h.size()); System.out.println("weakmap size: " + w.size()); System.out.println("Hashmap value: " + h.get("hashkey") + "\t" + "weakmap value: " + w.get("weakkey")); System.out.println(h.entrySet()); System.out.println(w.entrySet()); } } ``` Output is: ``` Before hashmap size: 1 weakmap size: 1 Hashmap value: 1 weakmap value: 1 null null After hashmap size: 1 weakmap size: 0 Hashmap value: 1 weakmap value: null [hashkey=1] [] ``` But when String hkey = new String("hashkey"); String wkey = new String("weakkey"); is replaced with following code, output changes. ``` String hkey = "hashkey"; String wkey = "weakkey"; ``` Output is: ``` Before hashmap size: 1 weakmap size: 1 Hashmap value: 1 weakmap value: 1 null null After hashmap size: 1 weakmap size: 1 Hashmap value: 1 weakmap value: 1 [hashkey=1] [weakkey=1] ``` Question: Making String literal and String object 'null' impacts in different way in WeakHashMap. What is the reason?

Original source