views:

723

answers:

6

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?

+18  A: 

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;
}
Mnementh
+7  A: 

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.

cletus
A: 

I have nothing to add to Mnementh for the direct answer, but this post does bring up the question, Why in the world do you want to do this? If you want to test if two references are to the same object, just use a==b, there's no need to use hash codes. If you're building a hash table, why would you want to hash by the object id rather than the "value" of the object?

Well, I don't know what your application is. Maybe you have some good reason for this.

Jay
+1  A: 

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().

Jakub
A: 

Isn't that a violation of the Liskov Substitution Principle?

Helper Method
A: 

I too am not going to point you to System.identityHashCode(). The entire point of hashcode() and equals() is to test for equality of values not references. Take a look at String after a quick check if the other object is a string it proceeds to compare the arrays character by character. These are of course primitive characters which means equality, references dont apply here.

mP