What WeakHashMap is good for
The java class
WeakHashMap<K, V> represents mappings from keys
K to values
V in the same way as the other classes in the Java library that represent mappings. But in each (k, v) pair, it keeps only a weak reference to the key k, and it is implemented in such a way that if k disappears because of garbage collection, then the cell that formerly represented the pair (k, v) is removed from the mapping.
WeakHashMap as an attribute mapping – Yes
WeakHashMap an ideal class for associating attributes with objects – without modifying the objects themselves to add more instance variables. The weak references mean that the objects (playing the role of keys in the mapping) are not prevented from being garbage collected just because the table is associating some attributes with them, so that as soon as the rest of the program forgets about an object, the attribute table can forget about it too.
WeakHashMap as a unique instance table – No
WeakHashMap does not do well is to act as a cache or table of unique instances, because that needs a table where the values and not the keys are held as weak references. Suppose that we wanted to store
Font objects uniquely in our program, so that there was only one
Font object with a given name. In that case, instead of creating
Font objects at will, we might keep a table mapping names to fonts, so that we could find a
Font object with a given name if one had already been created. There are several reasons we might do this:
- to save the space that would be occupied by keeping multiple copies of essentially the same
- to save the time needed to compute multiple
Fontobjects when one would do, and
- to allow us to compare two
Fontobjects for equality by comparing their identities, not by the more expensive process of comparing their names character by character.
Assuming that the other attributes of a
Font object could be recomputed from its name, we could prevent a space leak by putting only a weak reference to the object into the table, so that the garbage collector could collect the object when it was no longer needed by the rest of the program.
Next time a
Font with that name was needed, we could make a new one, and the behaviour of weak references would ensure that the new font was again the only one in existence with the given name.
But this behaviour (weak references to values) is precisely what
WeakHashMap doesn't give you, and trying to use it for this purpose is wrong. If we add a new entry to the table with
table.put(name, new Font(name));
then neither the entry nor the
Font object will ever be deleted: the entry in the hash table contains a strong reference to the
Font object, which contains a strong reference to the name. Thus, the name is strongly reachable, and the weak reference to it from the hash table entry will never be destroyed.
If, on the other hand, we add a new entry with
table.put(new String(name), new Font(name));
then there is only the one (weak) reference to the newly created
String object, and that and the hash table entry can be deleted immediately, even if the
Font object is still in use.
That violates the requirement that there be only one extant
Font object with a given name.
It doesn't really help to wrap the
Font object in another weak reference, like this:
table.put(name, new WeakReference<Font>(new Font(name)));
Sure enough, while the
Font object remains strongly reachable, so will the string
name, and that will keep the hash table entry in existence; and when the
Font is no longer strongly reachable, that object can itself be reclaimed. But whether the entry in the table is deleted at that point will depend on whether the
name has any other strong references to it. And worse, if the
Font object is modified so that, instead of keeping a reference to its name, it recomputes the name when needed, then
name may cease to be strongly reachable even while the
Font object is still in use, and then the table (as before) does not guarantee uniqueness.
String is an immutable class, so we ought not to need to worry whether we are dealing with two equal instances or a single, shared instance. But the behaviour of the table makes that matter.
If we're going to wrap the
Font object in a weak reference, it would be better to use an ordinary
HashMap instead of a
WeakHashMap, because then the worry about disappearing entries would not arise. Of course, that does not solve the problem of deleting hash table entries when they become useless. For that, a new and different hash table class is needed.