Thursday, November 20, 2008

Never hashCode on a mutable value.

public class Terrible {
 public static void main(String[] args) {
  HashSet people = new HashSet();
  Person originallyMike = new Person("Mike");
  people.add(originallyMike);
  System.out.println("Terrible.main: Contains Mike? " + people.contains(new Person("Mike")));
  System.out.println("Terrible.main: Changing stored name from Mike to Adam.");
  originallyMike._name = "Adam";
  System.out.println("Terrible.main: Contains Mike? " + people.contains(new Person("Mike")));
  System.out.println("Terrible.main: Contains Adam? " + people.contains(new Person("Adam")));

 }

 public static class Person {
  public String _name;

  public Person(String name) {
   _name = name;
  }

  @Override
  public int hashCode() {
   return _name.hashCode();
  }

  @Override
  public boolean equals(Object obj) {
   return obj instanceof Person && ((Person) obj)._name.equals(_name);
  }
 }
}
prints:
Terrible.main: Contains Mike? true
Terrible.main: Changing stored name from Mike to Adam.
Terrible.main: Contains Mike? false
Terrible.main: Contains Adam? false
HashSet uses the hashcode of your object to select the bucket for your object. If your hashCode changes, the object effectively disappears from the collection for the purposes of API calls like .contains(..). So do yourself a favor and never use a mutable value in your .hashCode (which also, incidentally, means that you can't use a mutable value in your .equals(..) since those two methods are required to be mutually consistent).

1 comment:

Anonymous said...

awesome post Mike. Really interesting!!!