An Ideal Hash Algorithm


Java already provides a good hashCode implementation for the class String, which is more often than not the key type for a HashMap. The integral numeric wrapper classes (Integer, Long, Byte, Char, Short) are also often used as a HashMap key; their hash code is simply the number they wrap.

The fields that uniquely identify your object are typically one of these object types (String or numeric). To obtain a decent hash code that satisfies the equality condition, you can simply return the hash code of the unique key. If more than one field is used to represent the unique key, you will need to devise an algorithm to generate the hash code.

The following code, to be added to the Course class, generates a hashCode based on arithmetically combining the hashCodes of department and number. Hash code algorithms typically use prime numbers. The use of primes tends to give better distribution when combined with the modulus operation against the table size.

 @Override public int hashCode() {    final int hashMultiplier = 41;    int result = 7;    result = result * hashMultiplier + department.hashCode();    result = result * hashMultiplier + number.hashCode();    return result; } 

The tests should pass once you implement this hashCode method.[8] Separate the hash code tests into a new test method that will enforce the complete contract for hashCode.

[8] This algorithm was obtained from the example at http://mindprod.com/jgloss/hashcode.html.

 public void testHashCode() {    Course courseA = new Course("NURS", "201");    Course courseAPrime = new Course("NURS", "201");    Map<Course, String> map = new HashMap<Course, String>();    map.put(courseA, "");    assertTrue(map.containsKey(courseAPrime));    assertEquals(courseA.hashCode(), courseAPrime.hashCode());    // consistency    assertEquals(courseA.hashCode(), courseA.hashCode()); } 

The test proves that two semantically equal courses produce the same hash code. It also demonstrates consistency. The return value from hashCode is the same (consistent) with each call to it, as long as the key values for the courses do not change.

The part of the test that demonstrates stuffing the Course into a hash map can be removed, since the contract assertions for hashCode are all that is required. The final set of equality and hash code contract tests:

 public void testEquality() {    Course courseA = new Course("NURS", "201");    Course courseAPrime = new Course("NURS", "201");    assertEquals(courseA, courseAPrime);    Course courseB = new Course("ARTH", "330");    assertFalse(courseA.equals(courseB));    // reflexivity    assertEquals(courseA, courseA);    // transitivity    Course courseAPrime2 = new Course("NURS", "201");    assertEquals(courseAPrime, courseAPrime2);    assertEquals(courseA, courseAPrime2);    // symmetry    assertEquals(courseAPrime, courseA);    // consistency    assertEquals(courseA, courseAPrime);    // comparison to null    assertFalse(courseA.equals(null));    // apples & oranges    assertFalse(courseA.equals("CMSC-120")); } public void testHashCode() {    Course courseA = new Course("NURS", "201");    Course courseAPrime = new Course("NURS", "201");    assertEquals(courseA.hashCode(), courseAPrime.hashCode());    // consistency    assertEquals(courseA.hashCode(), courseA.hashCode()); } 

These tests contain a good amount of code! Again, consider JUnit-addons (see footnote 6 above) as a way of automatically enforcing equality and hash code contracts. If you choose to not use JUnit-addons, make sure you refactor to eliminate duplication when writing these tests.



Agile Java. Crafting Code with Test-Driven Development
Agile Javaв„ў: Crafting Code with Test-Driven Development
ISBN: 0131482394
EAN: 2147483647
Year: 2003
Pages: 391
Authors: Jeff Langr

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net