Valid Java-overwrite equals
When do I not need to overwrite equals? Every instance of the class is unique in nature. We do not need to express it with special logical values. The equals method provided by the Object is correct. The superclass already covers equals, and the behavior inherited from the superclass is also suitable for the subclass. When the equals method of this class is determined not to be called, for example, the class is private. When do I need to overwrite equals? The answer is exactly the opposite of the previous question. That is, the class requires a unique logical equality concept, and the equals provided by the superclass does not satisfy its own behavior. (PS: for enumeration, equal logic and equal object are the same thing .) Since equals has to be overwritten, we need to follow some rules: reflexive: For any non-null reference value x, x. equals (x) is true. Symmetric Ric: For any non-null reference values x and y, if x. equals (y) is true, y. equals (x) is true. Transitive: For any non-null reference values x, y, and z, when x. equals (y) is true and y. if equals (z) is true, x. equals (z) is true. Consistent: For any non-null reference values x and y, as long as the information used in the comparison operation of equals in the object is not modified, multiple calls of x. the equals (y) results are consistent. (PS: For any non-null reference value x, x. equals (null) must return false .) In fact, these rules are easy to understand. The difficulty is that I may violate another rule when complying with one rule. It's hard to think that someone will violate this point. The following is a negative example of symmetry: class CaseInsensitiveString {private final String s; public CaseInsensitiveString (String s) {if (s = null) this. s = StringUtils. EMPTY; else this. s = s ;}@ Override public boolean equals (Object obj) {if (obj instanceof CaseInsensitiveString) return s. equalsIgnoreCase (CaseInsensitiveString) obj ). s); if (obj instanceof String) return s. equalsIgnoreCase (String) obj); return fa Lse ;}} this example apparently violates symmetry, that is, x. equals (y) is true but y. equals (x) is false. Not only is this type displayed when it is put as a wildcard in a set or another place, it will be unpredictable. For the above example, I will not involve other types in the equals method, so I can remove the String Instance's judgment. About the transmission, that is, when x. equals (y) is true and y. equals (z) is true, x. equals (z) is true. This rule is especially evident in class extension. For example, I use x and y to describe a Point: class Point {private final int x; private final int y; public Point (int x, int y) {super (); this. x = x; this. y = y ;}@ Override public boolean equals (Object obj) {if (! (Obj instanceof Point) return false; Point p = (Point) obj; return p. x = x & p. y = y ;}} now I want to add Color to Point: class ColorPoint extends Point {private final color Color; public ColorPoint (int x, int y, color Color) {super (x, y); this. color = color;} @ Override public boolean equals (Object obj) {if (! (Obj instanceof ColorPoint) return false; return super. equals (obj) & (ColorPoint) obj ). color = color ;}} it seems natural that the ColorPoint equals method is provided, but its symmetry is not satisfied. So we modified it to satisfy the symmetry: @ Overridepublic boolean equals (Object obj) {if (! (Obj instanceof Point) return false; if (! (Obj instanceof ColorPoint) return obj. equals (this); return super. equals (obj) & (ColorPoint) obj ). color = color;}. Now let's take the transmission into consideration. For example, we now have three instances, one Point and two ColorPoint .... then it is obvious that it does not meet <when x. equals (y) is true and y. if equals (z) is true, x. equals (z) is true>. In fact, we cannot extend the instantiated class while adding new value components and retaining the equals conventions. So I simply don't need instanceof, instead use getClass (). This can indeed solve the problem, but it is very unacceptable. If a subclass does not overwrite equals, The equals result is always false. In this case, I gave up inheritance and switched to composition ). The preceding ColorPoint is used as an example to convert a Point into a ColorPoint field instead of being extended. The Code is as follows: public class ColorPoint {private final Point point; private final Color color; public ColorPoint (int x, int y, Color color) {if (color = null) throw new NullPointerException (); point = new Point (x, y); this. color = color;}/*** Returns the point-view of this color point. */public Point asPoint () {return point;} @ Override public boolean equals (Object o) {if (! (O instanceof ColorPoint) return false; ColorPoint cp = (ColorPoint) o; return cp. point. equals (point) & cp. color. equals (color) ;}@ Override public int hashCode () {return point. hashCode () * 33 + color. hashCode () ;}} for consistency, that is, if the two are equal, they are always equal unless one party is modified. This is not so much about the equals method as it is about writing a class. This class should be designed to be variable or immutable. If it is immutable, consistency must be ensured.