It is known that the properties that equals () should satisfy cannot be satisfied by simply implementing the equals () method of a class that has an inheritance relationship as shown below [(Supplement 1)](# Supplement 1). .. [* 1 Reference](# 1) The workaround is also described in the same reference [(Supplement 2)](# Supplement 2), but the solution from another document [* 2 Reference](# 2) is described.
Create a two-argument equals () static method as shown below, and call Object.equals () through it. The important part is the part that calls equals () of both classes. This can be used outside of this class structure. Full text By the way, there is Objects.equals (Object, Object) in the standard API, but only equals () on the left side is called.
ObjectUtil.java
final class ObjectUtil {
private ObjectUtil() { throw new AssertionError("Not intended to be instanciated"); }
public static boolean equals(final Object lhs, final Object rhs) {
//Same if the reference destinations on the left and right sides are the same
if (lhs == rhs) return true;
//Same if both left and right references are null
if (lhs == null && rhs == null) return true;
//Not the same if either the reference destination on the left side or the reference destination on the right side is null
if (lhs == null || rhs == null) return false;
//If the reference destinations on the left and right sides are the same class, equals of that class()To return
if (lhs.getClass() == rhs.getClass()) return lhs.equals(rhs);
//If the references on the left and right sides are different classes, equals of both classes()And return
return lhs.equals(rhs) && rhs.equals(lhs);
}
}
// 1.Symmetry cannot be satisfied
// ->If you swap the right and left sides, the result will be different.
//Example using the class structure shown above
Point1D p1 = new Point1D(0);
Point2D p2 = new Point2D(0, 0);
assert(p1.equals(p2) == true); //True because only x values are compared
assert(p2.equals(p1) == false); //False to determine that it is a Point2D instance
// 2.Transitiveness cannot be satisfied
// -> p1 == p2 && p2 ==Even for p3, p1==Does not become p3
//Example using the class structure shown above
//Premise: Point2D.equals()Add the following to the specifications
//True even if the argument is Point1D or its subclass and the x value is the same
Point2D p1 = new Point2D(0, 0);
Point1D p2 = new Point1D(0);
Point2D p3 = new Point2D(0, 1);
assert(p1.equals(p2) == true); //True due to new specifications
assert(p2.equals(p3) == true); //true because x values are not compared
assert(p1.equals(p3) == false); // x,false to compare y values
// 3.Liskov substitution principle cannot be met
// ->Similar behavior is expected in subclasses, but not
//Example using the class structure shown above
//Assumption 1: Point1D.equals()Change the specifications as follows
//True only if the argument is Point1D and the x value is the same
//Assumption 2: CountingPoint1D.equals()Change the specifications as follows
//True only if the argument is CountingPoint1D and the x value is the same
Point1D p1 = new Point(0);
CountingPoint1D cp1 = new CountingPoint(0);
CountingPoint1D cp2 = new CountingPoint(0);
List<CountingPoint1D> list = Arrays.asList(cp1);
assert(list.contains(cp2) == true); // cp1 ==true for cp2
assert(list.contains(p1) == false); //False because of assumption 1
//Use composition instead of inheritance
//Example
class Point2D {
private final Point1D p1;
private final int y;
...
@Override
public boolean equals(Object o) {
if (!(o instanceof Point2D)) return false;
Point2D rhs = (Point2D)o;
return p1.equals(rhs.p1) && y.equals(rhs.y);
}
}
*1 Joshua Bloch (2014) "Effective Java 2nd Edition" Maruzen. Item 8 *2 Andrei Alexandrescu (2013) "The D Programming Language D" Shoeisha. 6.8.3
Recommended Posts