Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

hashCode and Aggregation

Is there a standard meta-algorithm or best practice of how to implement the hashCode() method for classes that are composed of other classes:

class A { B b; C c;  ... }

If we assume that B and C put some effort in implementing their hashCode(), it is certainly a good idea to base As hashcode on that of B and C. But how to best combine them?

I ask this because certain operations are obviously not well suited like in:

class Naive {
   B b1, b2;
   public int hashCode() { return b1.hashCode() ^ b2.hashCode(); }
}

This would cause a hash code of 0 for every Naive object that happens to have two equal B objects.

like image 788
Ingo Avatar asked May 03 '26 20:05

Ingo


2 Answers

This is a common pattern, which some Eclipse plug-ins are able to generate:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((b1 == null) ? 0 : b1.hashCode());
    result = prime * result + ((b2 == null) ? 0 : b2.hashCode());
    // repeat for other attributes you want to include...

    return result;
}

Don't forget to code the equals() method accordingly...

like image 146
nwinkler Avatar answered May 05 '26 08:05

nwinkler


nwinkler's algorithm (which is in fact what would be generated by Eclipse when using the Source > Generate hashcode and equals... functionality) is similar to what Joshua Bloch describes in Effective Java (as referenced in Puce's answer).

The idea is to combine hashcodes computed for significant fields. The use of the odd prime number 31 can result in a jvm optimization of the multiplication (into a shift + substraction). Note that you must exclude fields that are not used in equals() from this hashcode computation. You may exclude fields whose values are computed from fields included in the computation.

The suggested hashcode computation for an Object field is simply to recursively call its hashcode method, provided it is not null (in which case we use 0) and the object's equals() method is itself recursively called in our equals() method. If the latter is not the case (equals does a more complex comparison on our object field), suggested approach is to construct a canonical representation and compute an hashcode for it.

To compute an hashcode for primitive fields, following methods are suggested (note that they must still be combined into the result by doing result = result * prime + fieldHashCode):

  • float: Float.floatToIntBits(f)
  • int, byte, char, short: (int) f
  • long => (int) (f ^ (f>>>32))
  • boolean: (f?1:0)
  • double: longHash= Double.doubleToLongBits(f) then use (int) (longHash^(longHash>>>32))
  • arrays: in java 1.5, some hashCode methods where introduced in the Arrays class. you can also apply previous rules recursively on the elements of the array as if they were fields themselves.
like image 27
Simon Baslé Avatar answered May 05 '26 10:05

Simon Baslé



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!