hjfreyer
hjfreyer

Reputation: 569

Java hashcode based on identity

The default behavior of Object.hashCode() is to return essentially the "address" of the object so that a.hashCode() == b.hashCode() if and only if a == b. How can I get this behavior in a user-defined class if a superclass already defines hashCode()? For instance:

class A {
  public int hashCode() {
    return 0;
  }
}

class B extends A {
  public int hashCode() {
    // Now I want to return a unique hashcode for each object.
    // In pythonic terms, it'd look something like:
    return Object.hashCode(this);
  }
}

Ideas?

Upvotes: 11

Views: 2491

Answers (3)

Mnementh
Mnementh

Reputation: 51311

System.identityHashCode(Object) provides this behaviour.

You would write this:

class B extends A {
  public int hashCode() {
    return System.identityHashCode(this);
  }
}

Please check the equals-method, that it only returns true, if the two objects are the same. Otherwise it would break behaviour described for equals and hashCode. (To be correct, the equals-method has to return false, if you get different hashcodes for two objects.) To provide an implementation of equals() that comply with the given hashCode()-method:

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

Upvotes: 26

Jakub
Jakub

Reputation: 165

As Mnementh said it all, I'd just like to point out that hashCode() returning 0 (or any constant value) is valid (while lame). hashCode() can (and should) return different values for a and b only if !a.equals(b).
So for example you have

class A {
  public int hashCode() {
    return 0;
  }
  public boolean equals(Object o) {
    return o instanceof A; // all objects are equal
  }
}

class B extends A {
  public int hashCode() {
    return System.identityHashCode(this);
  }
  public boolean equals(Object o) {
    return this.hashCode().equals(o.hashCode());
  }
}

Now you create two objects:

A a = new A();
A b = new B();

And suddenly a.equals(b), but !b.equals(a). Of course in more real life the equals() in A will be more sophisticated, but the problem still persist. To get rid of this problem you want to always call

if (super.equals(o)) return true;

at the beginning of new equals().

And since overriding hashCode() is strictly tied to overriding equals(), you want to make sure that everywhere super.equals() returned true for any two given objects, new hashCode() will return super.hashCode().

Upvotes: 1

cletus
cletus

Reputation: 625097

Use System.identityHashCode(). This is what IdentityHashMap uses.

You should be extremely wary of overriding an existing hashCode() with this though because you might break the hashCode contract, being that two objects that:

if a.equals(b) then a.hashCode() must equal b.hashCode()

You might break this by overriding the existing behaviour or you might need to override equals() too.

Upvotes: 9

Related Questions