HashCode for conditional equals

I would like to generate a hash-code for the following equals-method.

public MyClass class {

  private int a;
  private final String b;

  public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof MyClass)) return false;

        MyClass myClass = (MyClass) o;
        return a == myClass.a || (b == null ? myClass.b == null : b.equals(myClass.b));
  }

  @Override
  public int hashCode() {
      int result = (int) (a^ (a >>> 32));
      result = 31 * result + (b != null ? b.hashCode() : 0);
      return result;
  }

}

The catch is that equals returns true in a single or both of 2 cases: either o1.a == o2.a or o1.b == o2.b. In such a case usual hash won't be the same for: myClass("a", "b") and myClass("a", null)

Jon Skeet
people
quotationmark

Forget the hash - your equality comparison is fundamentally broken to start with.

Consider three values:

foo: a=10, b=0
bar: a=10, b=5
baz: a=20, b=5

Now:

foo.equals(bar) => true because of a
bar.equals(baz) => true because of b
foo.equals(baz) => false because neither a nor b match

This violates the transitivity requirements of Object.equals:

for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.

If you don't have transitivity, it's going to be really hard to come up with a valid hashCode implementation other than returning a constant (which is valid, but not exactly useful).

people

See more on this question at Stackoverflow