Dangers of using WeakReference/SoftReference in Hash-based collections

Hey everyone,

Just a quick post about something I saw this morning. In FriendCaster we use a HashMap collection of SoftReference’d Bitmap’s as an in-memory cache for images. This works fairly well as it means that we can get access to the bitmaps from memory (if they’re still in there). While looking through the source for Reference (super class of WeakReference and SoftReference) I saw that it does not override equals or hashcode.

This means that trying to use the Reference class for hashing/equals will not work as expected, and will not compare against it’s referenced object. Please note, this only matters if you’re using the Reference class for the hash, using a HashMap<String,SoftReference<?» is fine as it’s the String being hashed (as the key). If you’re using a HashSet though, or call equals on the Reference, it does affect you.

Anyway, here’s a quick class I just knocked up to fix this. It basically just delegate the equals and hashCode methods to it’s reference object:

public class WeakEqualReference<T> extends WeakReference<T> {

	public WeakEqualReference(T r) {
		super(r);
	}

	@SuppressWarnings("unchecked")
	@Override
	public boolean equals(Object other) {

		boolean returnValue = super.equals(other);

		// If we're not equal, then check equality using referenced objects
		if (!returnValue && (other instanceof WeakEqualReference<?>)) {
			T value = this.get();
			if (null != value) {
				T otherValue = ((WeakEqualReference<T>) other).get();

				// The delegate equals should handle otherValue == null
				returnValue = value.equals(otherValue);
			}
		}

		return returnValue;
	}

	@Override
	public int hashCode() {
		T value = this.get();
		return value != null ? value.hashCode() : super.hashCode();
	}
}