4

I have a class that will be used in a HashSet. It only contains two members, and both are of the same type interface. This is what it looks like:

class MyClass{
    MyInterface a;
    MyInterface b;

    public int hashCode(){
         return a.hashCode() + b.hashCode();
    }

    public boolean equals(Object obj){
         if(!(obj instanceof MyClass)
              return false;
         MyClass other (MyClass) obj;
         return (this.a == other.a && this.b == other.b) || (this.a == other.b && this.b == other.a);
    }
}

As you can see, two instances of MyClass are "equal" if they contain the same two instances of MyInterface.

Now, I was thinking that for hashCode(), I could just add up the default hashcodes of its members. Is this good enough? If not, what is a proper implementation of hashCode() for this case?

10
  • how is a and b's hashcode defined ? Commented Jun 11, 2015 at 19:19
  • 1
    This will provide an unequal hashcode distribution: elements around Integer.MaxValue / 2 will be disproportionally represented compared to those at the extremes, leading to more hash collisions. Commented Jun 11, 2015 at 19:19
  • 2
    You could also use: return Objects.hash(a, b); Commented Jun 11, 2015 at 19:24
  • 2
    @assylias no, that would give two different hashcodes for equal objects, because [a, b] is equal to [b, a] Commented Jun 11, 2015 at 19:26
  • 2
    @assylias the OP appears to require something order-agnostic which Objects.hash is not Commented Jun 11, 2015 at 19:26

3 Answers 3

3

Yes, this is perfectly fine. It's equivalent to the implementation of Set.hashCode() for two-element sets.

Sign up to request clarification or add additional context in comments.

2 Comments

@River: Like I commented elsewhere, assuming a.hashCode() and b.hashCode() have proper hash code implementations that offer proper value distribution to begin with, I really don't see how the extra calculation will help reduce the likelihood of collisions. OP's implementation is fine.
That being said, you could almost certainly do better (less-collisions) with a finer-tuned hash function. The real question is whether it's worth your time to optimize this function rather than simply stick with one that is "good enough".
1

I would say no. Wouldn't this mean that these two instances of MyClass would hash to the same value:

MyClass {
  a.hashCode = 2;
  b.hashCode = 3;
}

and

MyClass {
  a.hashCode = 1;
  b.hashCode = 4;
}

6 Comments

So you have a hash collision. So what? Do you have a better suggestion?
This is bound to happen... Perfect hash functions are near impossible
Maybe my example is overly simplistic, but it seems like a more complete implementation could minimize the number of collision. Do I have a better suggestion? No.
You could do a combination of + and *, which are both associative and commutative (which are required): (a.hashCode() + b.hashCode()) * 31 + (a.hashCode() * b.hashCode()).
@Clashsoft: Assuming a.hashCode() and b.hashCode() have proper hashcode implementations that offer proper value distribution to begin with, I don't see any compelling reason to complicate the calculation.
|
0

Yes it is.

Because even with hashCode collision, the docs state:

It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.