(Java) How to implement equals () for a class with value elements added by inheritance

Introduction

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. equals_impl.png

Conclusion

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);
    }
}

Supplement 1

// 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

Supplement 2

//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

(Java) How to implement equals () for a class with value elements added by inheritance
Mapping to a class with a value object in How to MyBatis
[Java] How to compare with equals method
[Java] How to search for a value in an array (or list) with the contains method
[Java] How to turn a two-dimensional array with an extended for statement
[Java] [For beginners] How to insert elements directly in a 2D array
[Java] How to test for null with JUnit
How to convert a solidity contract to a Java contract class
[Java] How to get HashMap elements by loop control using extended for statement
[Java] How to get a request by HTTP communication
[Java] How to cut out a character string character by character
[Java] How to start a new line with StringBuilder
How to use java class
[Java] How to implement multithreading
How to create a lightweight container image for Java apps
How to test a private method with RSpec for yourself
How to move another class with a button action of another class.
Investigated how to call services with Watson SDK for Java
How to make a Java container
How to disassemble Java class files
How to implement a job that uses Java API in JobScheduler
[Java] How to create a folder
How to change arguments in [Java] method (for those who are confused by passing by value, passing by reference, passing by reference)
How to decompile java class files
[Java] How to use LinkedHashMap class
Replace with a value according to the match with a Java regular expression
How to use class methods [Java]
How to check for the contents of a java fixed-length string
How to make a Java array
How to make a groundbreaking diamond using Java for statement wwww
How to deal with the type that I thought about writing a Java program for 2 years
[Java] How to use Math class
How to implement a slideshow using slick in Rails (one by one & multiple by one)
[Personal memo] How to interact with a random number generator in Java
[Rails] How to log in with a name by adding a devise name column
How to find out the Java version of a compiled class file
[Java small story] Monitor when a value is added to the List
[Java] How to get to the front of a specific string using the String class
How a completely inexperienced person studied to acquire Java silver by himself
How to track when a bucket managed by scoop changes (mainly Java)
How to make an app with a plugin mechanism [C # and Java]
How to make a Java calendar Summary
How to implement date calculation in Java
How to implement Kalman filter in Java
[Java] How to use the File class
How to compile Java with VsCode & Ant
[Java] How to use the HashMap class
[Introduction to Java] How to write a Java program
How to create a Maven repository for 2020
How to make a Discord bot (Java)
How to implement coding conventions in Java
[Processing × Java] How to use the class
How to implement TextInputLayout with validation function
How to print a Java Word document
How to use Java Scanner class (Note)
[Java] How to use the Calendar class
I tried to make a program that searches for the target class from the process that is overloaded with Java
How to output jar with main class specified by gradle in Intellij IDEA
How to deploy a system created with Java (Wicket-Spring boot) to an on-campus server
How to test a class that handles application.properties with SpringBoot (request: pointed out)
Add class only to specific elements with V-for