Inheritance Java equality check

By , last updated August 11, 2019

We’ve earlier written a post about Recipe for a high-quality “equals” method. This is harder to get right in the case of inheritance.

As it says here the contract of the equals method in Object specifies that equals must implement an equivalence relation on non-null objects:

  • It is reflexive: for any non-null value x, the expression x.equals(x) should return true.
  • It is symmetric: for any non-null values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
  • It is transitive: for any non-null values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
  • It is consistent: for any non-null values x and y, multiple invocations of x.equals(y) should consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
  • For any non-null value x, x.equals(null) should return false.

Consider two classes: A and B that extends class A.

public class A {

}

public class B extends A {

}

Now, if we have two objects of type B with different values from class A, then these two objects can not be equal. That means that we cannot not to take into consideration equals method from class A when writing an equals method for class B:


public class A {
	private String id;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	@Override
	public int hashCode() {
		return Objects.hash(id);
	}

	@Override
	public boolean equals(Object obj) {
		if(obj == null) {
			return false;
		}

		if(!(obj instanceof A)) {
			return false;
		}

		A other = (A)obj;
		return Objects.equals(this.id, other.id);
	}
}

public class B extends A {
	private String id;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	@Override
	public int hashCode() {
		return Objects.hash(super.hashCode(), id);
	}

	@Override
	public boolean equals(Object obj) {
		if(obj == null) {
			return false;
		}

		if(!(obj instanceof B)) {
			return false;
		}

		B other = (B)obj;
		return super.equals(obj)
			&& Objects.equals(this.id, other.id);
	}
}

We added super.hashCode() in hashCode method and super.equals(obj) in equals in order to implement the right equality check.

A good thing in this design will be to make class A abstract then there won’t be logic problems when comparing A and B like this:
A.equals(B)
B.equals(A)

Senior Software Engineer developing all kinds of stuff.