Un-overriding hashCode in Java

Problem: you are inheriting from a class in Java. This class has overridden Object.hashCode(). However, you do not want the behaviour of the overriding method, but rather that of the original implementation in the Object class.

Solution: in your new class, create a private field of type Object. Override the hashCode() method in the class to call hashCode() on that field. The result should follow a pattern similar to that below:

public class CustomHashSet<T> extends HashSet<T> {
    private Object hasher;

    public CustomSpecHashSet() {
        super();
        hasher = new Object();
    }
    @SuppressWarnings("unchecked")
    public synchronized Object clone() {
        CustomHashSet<T> copy = (CustomHashSet<T>)super.clone();
        copy.hasher = new Object();
        return copy;
    }

    public int hashCode() { return hasher.hashCode(); }

    public boolean equals(Object o) { return this == o; }
}

Discussion

In Java, once a method has been overridden, it is impossible to get at the original implementation from any inheriting classes. I recently had to deal with this when I wanted to keep some objects that inherited from various Collections inside HashSets, and wanted distinct objects in the set to not be treated as equals just because they happened to contain the same elements. In other words, I needed to use the Object implementations of the hashCode() and equals() methods, rather than the versions defined by the Collections. This is because Object.hashCode() returns a unique integer for every distinct object (typically by using the memory address of an object).

At first, I thought this problem could be solved with reflection. The soloution should simply involve getting a Method instance for Object.hashCode(), and invoke that on any object. Unfortunately, that does not work; calling a method using reflection in Java results in a dynamic method lookup based on the object the method is being invoked on.

Since Java does not permit un-overriding methods, one has to cheat. An object that is never leaked to the outside world can be used to provide a unique integer for each instance. However, care must be taken when implementing classes that support cloning (i.e. implement the Cloneable interface, or inherit from a class that does). Since the clone() method only does a shallow copy of an object, it is essential to override clone(), and make sure that any copies created there get their own instance of the hashing object. There is another gotcha; in the presense of multiple threads accessing the same object, the following clone() implementation would be unsafe:

public Object clone() {
    MyObject copy = (MyObject)super.clone();
    copy.hasher = new Object();
    return copy;
}

This is because the Java memory model only guarantees initialization safety for objects created using a constructor. What this means is that, for an object created using clone() and changing fields after the call to clone(), the updates to those fields are not guaranteed to be seen immediately by other threads accessing that object. A simple way to address this is to put the initialization of the cloned object inside a synchronized block, as in the code given at the top of this recipe.