Note: The mercurial server is disabled at the moment while I investigate whether it can run with an acceptably low CPU load – Mike.
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
That makes 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
What 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
Font
object, - to save the time needed to compute multiple
Font
objects when one would do, and - to allow us to compare two
Font
objects 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 String
object 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.