Well, HomoSapiens#hashcode will be enough with CPerkins answer.
@Override public int hashCode() { int hash = super.hashCode(); hash = 89 * hash + Objects.hash(name); hash = 89 * hash + Objects.hash(faceBookNickname); return hash; }
If you want these parent fields ( gender , weight , height ) in action, one way creates the actual instance of the parent type and uses it. Thank God this is not an abstract class.
@Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final HomoSapiens other = (HomoSapiens) obj; if (!super.equals(new Hominidae( other.gender, other.weight, other.height))) { return false; } if (!Objects.equals(name, other.name)) return false; if (!Objects.equals(faceBookNickname, other.faceBookNickname)) return false; return true; }
I am adding a way (I think) to solve this. The key point is to add a method that freely checks equality.
public class Parent { public Parent(final String name) { super(); this.name = name; } @Override public int hashCode() { return hash = 53 * 7 + Objects.hashCode(name); } @Override public boolean equals(final Object obj) { return equalsAs(obj) && getClass() == obj.getClass(); } protected boolean equalsAs(final Object obj) { if (this == obj) return true; if (obj == null) return false; if (!getClass().isAssignableFrom(obj.getClass())) return false; final Parent other = (Parent) obj; if (!Objects.equals(name, other.name)) return false; return true; } private final String name; }
And here comes the Child .
public class Child extends Parent { public Child(final String name, final int age) { super(name); this.age = age; } @Override public int hashCode() { return hash = 31 * super.hashCode() + age; } @Override public boolean equals(final Object obj) { return super.equals(obj); } @Override protected boolean equalsAs(final Object obj) { if (!super.equalsAs(obj)) return false; if (!getClass().isAssignableFrom(obj.getClass())) return false; final Child other = (Child) obj; if (age != other.age) return false; return true; } private final int age; }
Testing...
@Test(invocationCount = 128) public void assertReflective() { final String name = current().nextBoolean() ? "null" : null; final int age = current().nextInt(); final Child x = new Child(name, age); assertTrue(x.equals(x)); assertEquals(x.hashCode(), x.hashCode()); } @Test(invocationCount = 128) public void assertSymmetric() { final String name = current().nextBoolean() ? "null" : null; final int age = current().nextInt(); final Child x = new Child(name, age); final Child y = new Child(name, age); assertTrue(x.equals(y)); assertEquals(x.hashCode(), y.hashCode()); assertTrue(y.equals(x)); assertEquals(y.hashCode(), x.hashCode()); } @Test(invocationCount = 128) public void assertTransitive() { final String name = current().nextBoolean() ? "null" : null; final int age = current().nextInt(); final Child x = new Child(name, age); final Child y = new Child(name, age); final Child z = new Child(name, age); assertTrue(x.equals(y)); assertEquals(x.hashCode(), y.hashCode()); assertTrue(y.equals(z)); assertEquals(y.hashCode(), z.hashCode()); assertTrue(x.equals(z)); assertEquals(x.hashCode(), z.hashCode()); }