Image Image Image Image Image
Scroll to Top

To Top

Android

20

Dec
2011

2 Comments

In Android

By Chris Banes

Dangers of using WeakReference/SoftReference in Hash-based collections

On 20, Dec 2011 | 2 Comments | In Android | By Chris Banes

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();
	}
}

  • Pingback: Image Caching | senab

  • Guest

    There’s actually a reason they don’t override that: it can change over the lifetime of the instance, which is essentially a no-no.

    Assume the reference has been cleared. You might end with multiple keys in your map having the same hashCode and being mutually equal, while being different instances. Not good at all.

    Have a look at java.util.WeakHashMap for how to do this properly.