Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: Only check hashCode in equals() of immutable object

I have an immutable object, for example a node in the Cartesian space. The class is immutable, so I cache the hashCode for very fast hashing.

private final int hashCode;

private final double x, y, z;

public Node(final double x, final double y, final double z)
{
    this.x = x;
    this.y = y;
    this.z = z;
    this.hashCode = Objects.hashCode(this.x, this.y, this.z);
}

@Override
public boolean equals(final Object obj)
{
    if (this == obj) { return true; }
    if (obj == null) { return false; }
    if (!(obj instanceof Node)) { return false; }
    final Node other = (Node) obj;
    return Objects.equal(this.x, other.x) && Objects.equal(this.y, other.y) && Objects.equal(this.z, other.z);
}

@Override
public int hashCode()
{
    return this.hashCode;
}

Since the hashCode is unique and dependent on all fields of the class AND the class is Immutable, would it be correct to only check Node equality based on the hashCode?

@Override
public boolean equals(final Object obj)
{
    if (this == obj) { return true; }
    if (obj == null) { return false; }
    if (!(obj instanceof Node)) { return false; }
    final Node other = (Node) obj;
    return this.hashCode == other.hashCode;
}

This passes all Unit Tests I have written about the properties of equals() and hashCode() and their interaction, but perhaps there is something I am missing?

Note: Objects.hashCode() and Objects.equal() are Guava classes helpful for the respective methods.

like image 324
Alexander Karatarakis Avatar asked Apr 18 '12 00:04

Alexander Karatarakis


People also ask

Why we check hashCode () equality before equals () method?

If two objects are equal (i.e. the equals() method returns true), then they must have the same hash code. Otherwise, our methods would be meaningless. As we mentioned above, a hashCode() check should go first to improve performance.

Is it necessary to override hashCode and equals method?

You must override hashCode() in every class that overrides equals(). Failure to do so will result in a violation of the general contract for Object. hashCode(), which will prevent your class from functioning properly in conjunction with all hash-based collections, including HashMap, HashSet, and Hashtable.

What happens if we override only hashCode and not equals?

Only Override HashCode, Use the default Equals: Only the references to the same object will return true. In other words, those objects you expected to be equal will not be equal by calling the equals method. Only Override Equals, Use the default HashCode: There might be duplicates in the HashMap or HashSet.

Can you use hashCode in equals?

Java hashCode() An object hash code value can change in multiple executions of the same application. If two objects are equal according to equals() method, then their hash code must be same. If two objects are unequal according to equals() method, their hash code are not required to be different.


2 Answers

Nope; that won't work.

You have 232 possible hashcodes and 2192 possible values.

like image 74
SLaks Avatar answered Sep 17 '22 10:09

SLaks


No, but..

I guess you could check the hashcode to see whether objects are not equal and gain some performance there:

public boolean equals(final Object obj) {
   if (this == obj) { return true; }
   if (!(obj instanceof Node)) { return false; }
   final Node other = (Node) obj;

   if (this.hashCode != other.hashCode) {
      return false; // If hashcodes differ, we're sure the objects are not equal
   }
   // remainder of the actual equals implementation
}

Of course this will only improve performance in case most of your comparisons yield false. In case of equal objects, this will bring a performance penalty. In your example (comparing just three values), I wouldn't recommend this.

like image 42
bertvh Avatar answered Sep 18 '22 10:09

bertvh