Hashcode and Equals for object reference?

539 Views Asked by At

I have a somewhat niche need to key off two objects of generic types X and Y, and use that to return type T. I want to put these items in tightly managed HashMap and use that to look up on the X,Y key.

However, how do I ensure X and Y are hashcoded and equality compared on their memory reference, and not any overridden implementation of hashCode/equals?

public final class BiReferenceCache<X,Y,T> { 
    private final HashMap<Key<X,Y>,T> cacheMap = new HashMap<>();

    public T get(X item1, Y item2) { 
        return cacheMap.get(new Key<X,Y>());
    }

    private static final class Key<X,Y> { 
        private final X val1;
        private final Y val2;

        Key(X val1, Y val2) { 
            this.val1 = val1;
            this.val2 = val2;
        }

        public int hashCode() { 
            //??? What do I do to hashcode by val1 and val2's memory reference?
        }
        public boolean equals(Object obj) { 
            //??? What do I do to check equality for val1 and val2's memory reference?
        }
    }

}
5

There are 5 best solutions below

1
On BEST ANSWER

Use

System.identityHashCode

and

==
0
On

You should use for hashCode:

val1.hashCode() + val2.hashCode();

and for equals:

val1.equals(obj.val1) && val2.equals(obj.val2);

basically forwarding the responsibility.

PS: If null is allowed, you have to add the appropriate code.

0
On

You can use == to check memory identity and java.lang.System#identityHashCode(Object) to get the non-overriden hash code.

private static final class Key<X,Y> { 
    private final X val1;
    private final Y val2;

    Key(X val1, Y val2) { 
        this.val1 = val1;
        this.val2 = val2;
    }

    public int hashCode() { 
        return 31 * System.identityHashCode(val1) + System.identityHashCode(val2);
    }

    public boolean equals(Object obj) { 
        if (obj == null) {
            return false;
        }
        if (!obj instanceof Key) {
            return false;
        }
        Key other = (Key)obj;
        return val1 == other.val1 && val2 == other.val2;
    }
}
0
On

Shouldn't the == operator assert reference equality?

This question may answer your hashCode concerns: How do you get the "object reference" of an object in java when toString() and hashCode() have been overridden? (quoted below)

What exactly are you planning on doing with it (what you want to do makes a difference with what you will need to call)?

hashCode(),as defined in the Javadocs says:

As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.)

So if you are using the hashCode to find out if it is a unique object in memory that isn't a good way to do it.

System.identityHashCode does the following:

Returns the same hash code for the given object as would be returned by the default method hashCode(), whether or not the given object's class overrides hashCode(). The hash code for the null reference is zero.

Which, for what you are doing sounds like what you want... but what you want to do might not be safe depending on how the library is implemented.

0
On

For the hashCode() you could simply use: val1.hashCode() ^ val2hashCode(); (bytewise XOR operator ^) - not a great solution, but does what it should.

In equals() you should first check if both objects have identical references (with ==), then check that the objects you are comparing are not null. After that, make sure both objects are instances of the same type. And the last step: check if the attribute values of both are equal.

In case you have a superclass it would be considered as good style to deal with the first 3 steps in the superclass.