Is there a specific rule on how Overriding equals()
& hashCode()
in sub classes considering super fields ?? k
Well, HomoSapiens#hashcode
will be enough with CPerkins's 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 those parent's fields(gender
, weight
, height
) in action, one way is creating an actual instance of parent type and use it. Thank God, it's 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'm adding a way to (I think) solve this. The key point is adding a method loosely checks the 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());
}
The rules are:
from Object.equals().
So, use the fields needed to fulfill the rules.
I believe they now have a method that just does this for you :
EqualsBuilder.reflectionEquals(this, o);
HashCodeBuilder.reflectionHashCode(this);
It's worth noting that the IDE auto generation maybe has taken into consideration super class,just provided that the equals() and hashCode() of super class exists yet. That is, should auto generate these two functions of super first, and then auto generate of the child. I got below right example under Intellj Idea:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
TActivityWrapper that = (TActivityWrapper) o;
return data != null ? data.equals(that.data) : that.data == null;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (data != null ? data.hashCode() : 0);
return result;
}
The problem happens just when you don't auto generate super's in first. Please check above under Netbeans.