Building.hashCode()

From: R. Clayton <rclayton_at_monmouth.edu>
Date: Thu, 18 Nov 2010 11:25:24 -0500
For the second assignment, why is hashCode() overridden in Building?

  Ah, good question.  If you look at the javadoc for Object.hashCode(), you'll
  find the general contract for hashCode().  General contracts are part of the
  great lie I mentioned in class; they specify, but do not guarantee, expected
  behavior.  The second requirement in the hashCode() contract is

    If two objects are equal according to the equals(Object) method, then
    calling the hashCode method on each of the two objects must produce the
    same integer result.

  That is, there is an expected relation between equals() and hashCode(), and
  when changing the behavior of either one of those methods - by, for example,
  overriding it - you have to make sure the relation still holds.

  There's no good reason to override Object.hashCode() in Building; however,
  there's an excellent reason for overriding Object.equals(): it's too strict.
  Without overriding, 

    (new Building(1, 2, 3)).equals(new Building(1, 2, 3))

  returns false, which, while it makes sense given the definition of
  Object.equals(), is counter-intuitive and confusing with respect to Buildings
  (essentially, Object.equals() implements identity, while Building.equals()
  should implement similarity).  I overrode Building.equals() to make more
  sensible, which entailed the obligation to override Building.hashCode() to
  maintain the contract.

  Forgetting to override hashCode(), which is easy to do, causes things to
  break in mysterious and subtle ways.  Similar to the example above, the
  following code prints "true" then "null":

    Hashtable<Building, String> ht = new Hashtable<Building, String>()
    System.out.println((new Building(1, 2, 3)).equals(new Building(1, 2, 3)))
    ht.put(new Building(1, 2, 3), "hello")
    System.out.println(ht.get(new Building(1, 2, 3)))

  If I had forgotten to override hashCode(), and somebody used hashing in their
  assignment, which might be a sensible thing to do, they might have been in
  for some extremely confusing debugging.

  findbugs warns you when you override equals() but not hashCode().  Make a
  copy of Building.java, delete hashCode(), compile it, and run the class
  through findbugs.

  I once worked for a company on a compiler written in Java.  In almost every
  case, a class that overrode equals() failed to override hashCode().  One of
  my colleagues spend a couple of intense weeks working on an error, which he
  eventually tracked down to a misbehaving hash set.  The hash set was being
  used to count the number of unique items in a list.  This is a perfectly good
  use for sets: throw all the list items into a set, let the set semantics
  remove the duplicates, and then use the set size as the count.  You should be
  able to anticipate what was wrong:  the list items were instances of classes
  in which equals() was overridden but hashCode() was not.  As a result, the
  set size was too high, causing the problem.  Even after my colleague traced
  the problem to the set size, it took him a few days to figure out why the set
  wasn't working correctly.
Received on Thu Nov 18 2010 - 11:25:58 EST

This archive was generated by hypermail 2.2.0 : Sat Nov 27 2010 - 14:09:40 EST