import java.util.*; public class EqualsContract { public static void main(String[] args) { Person a = new Age ("Fred", 18); Person b = new Person("Fred"); Person c = new Age ("Fred", 21); Set s = new HashSet(); s.add(a); s.add(b); s.add(c); System.out.println("Set s = " + s); Set t = new HashSet(); t.add(b); t.add(a); t.add(c); System.out.println("Set t = " + t); } } class Person { private String name; public Person(String s) { name = s; } @Override public String toString() { return name; } @Override public int hashCode() { return 42; } @Override public boolean equals(Object o) { return (o instanceof Person) && name.equals(((Person) o).name); } } class Age extends Person { private int age; public Age(String s, int a) { super(s); age = a; } @Override public String toString() { return super.toString() + " " + age; } @Override public int hashCode() { return 42; } @Override public boolean equals(Object o) { return (o instanceof Age) && super.equals(o) && age == ((Age) o).age; } } /* equals() is not symmetric (although it is transitive). hashCode() is horribly inefficient, but is functionally correct. The point of this example is that the broken equals() method makes it impossible to predictably store Person objects in the collection framework. Note the output, where we would expect Sets s and t to be the same: cs1% java EqualsContract Set s = [Fred 21, Fred 18] Set t = [Fred 21, Fred 18, Fred] Ouch! */