JDK-6431610 : (coll) util.Hashing class
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.util:collections
  • Affected Version: 5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: linux
  • CPU: x86
  • Submitted: 2006-05-30
  • Updated: 2012-10-08
  • Resolved: 2010-02-12
Related Reports
Duplicate :  
Description
A DESCRIPTION OF THE REQUEST :
It would be convenient if there were a class in the library that helps with writing a hashCode() method.

JUSTIFICATION :
It's not obvious how to do good hashing.  Better algorithms can be invented in the future.  Everyone is writing their own copy of the same code (more or less).

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Methods in the library to help one write a good hashCode() method.
ACTUAL -
You're on your own.

CUSTOMER SUBMITTED WORKAROUND :
package util;

/**
 * Calculate a hash code.
 *
 * Algorithm is from Josh Bloch's book <quote>Effective Java</quote>.
 */
public class Hashing {

  private static final int MAGIC_PRIME1 = 17;
  private static final int MAGIC_PRIME2 = 37;

  /**
   * Make a hash code from a sequence of ints.
   *
   * @param field ints to be made into a hash code
   * @return the hash code
   */
  public static int makeHashCodeInt(int... field) {
    int result = initial();
    for (int i = 0; i < field.length; ++i) {
      int hashCode = field[i];
      result = next(result, hashCode);
    }
    return result;
  }

  /**
   * Make a hash code from sequence of objects.
   *
   * Note: should probably hard code Double because the standard implementation
   * uses Double.doubleToLongBits() instead of Double.doubleToRawLongBits()
   * and does only a simple xor.
   *
   * @param field objects and numbers to be made into a hash code
   * @return the hash code
   */
  public static int makeHashCode(Object... field) {
    int result = initial();
    for (int i = 0; i < field.length; ++i) {
      Object obj = field[i];
      int hashCode = obj == null ? 0 : obj.hashCode();
      result = next(result, hashCode);
    }
    return result;
  }

  /**
   * Provide the initial value for the hash code.
   *
   * @return hash code initial value
   */
  public static int initial() {
    return MAGIC_PRIME1;
  }

  /**
   * Combine a new value's hash code into the accumulated hash code.
   *
   * @param accumulatedHashCode the hash code so far
   * @param newHashCode the hash code to be combined
   * @return
   */
  public static int next(int accumulatedHashCode, int newHashCode) {
    return MAGIC_PRIME2 * accumulatedHashCode + newHashCode;
  }

  //============================================================================

  public static void main(String[] args) {
    Test test = new Test();
    System.out.println(test.hashCode());
  }
}

//==============================================================================

class Test {
  int foo = 2;
  Integer bar = 3;
  Test2 test2 = new Test2();
  Test3 test3 = new Test3();
  Test4 test4 = new Test4();
  Object baz;

  public int hashCode() {
    return Hashing.makeHashCode(foo, bar, test2, test3, test4, baz);
  }
}

//==============================================================================

class Test2 {
  int foo = 1;
  int bar = 2;

  public int hashCode() {
    // All fields are ints; no boxing required.
    return Hashing.makeHashCodeInt(foo, bar);
  }
}

//==============================================================================

class Test3 {
  int foo = 1;
  double bar = 2;

  public int hashCode() {
    // The double requires boxing.
    return Hashing.makeHashCode(foo, bar);
  }
}

//==============================================================================

class Test4 {
}

Comments
EVALUATION A method to conveniently produce resonable hash codes has added to java.util.Objects as part of the fix for bug 6891113.
12-02-2010

EVALUATION Worthy of consideration
30-05-2006