How to override equals method in Java

后端 未结 9 1568
自闭症患者
自闭症患者 2020-11-22 01:41

I am trying to override equals method in Java. I have a class People which basically has 2 data fields name and age. Now I want to ove

9条回答
  •  你的背包
    2020-11-22 02:06

    When comparing objects in Java, you make a semantic check, comparing the type and identifying state of the objects to:

    • itself (same instance)
    • itself (clone, or reconstructed copy)
    • other objects of different types
    • other objects of the same type
    • null

    Rules:

    • Symmetry: a.equals(b) == b.equals(a)
    • equals() always yields true or false, but never a NullpointerException, ClassCastException or any other throwable

    Comparison:

    • Type check: both instances need to be of the same type, meaning you have to compare the actual classes for equality. This is often not correctly implemented, when developers use instanceof for type comparison (which only works as long as there are no subclasses, and violates the symmetry rule when A extends B -> a instanceof b != b instanceof a).
    • Semantic check of identifying state: Make sure you understand by which state the instances are identified. Persons may be identified by their social security number, but not by hair color (can be dyed), name (can be changed) or age (changes all the time). Only with value objects should you compare the full state (all non-transient fields), otherwise check only what identifies the instance.

    For your Person class:

    public boolean equals(Object obj) {
    
        // same instance
        if (obj == this) {
            return true;
        }
        // null
        if (obj == null) {
            return false;
        }
        // type
        if (!getClass().equals(obj.getClass())) {
            return false;
        }
        // cast and compare state
        Person other = (Person) obj;
        return Objects.equals(name, other.name) && Objects.equals(age, other.age);
    }
    

    Reusable, generic utility class:

    public final class Equals {
    
        private Equals() {
            // private constructor, no instances allowed
        }
    
        /**
         * Convenience equals implementation, does the object equality, null and type checking, and comparison of the identifying state
         *
         * @param instance       object instance (where the equals() is implemented)
         * @param other          other instance to compare to
         * @param stateAccessors stateAccessors for state to compare, optional
         * @param             instance type
         * @return true when equals, false otherwise
         */
        public static  boolean as(T instance, Object other, Function... stateAccessors) {
            if (instance == null) {
                return other == null;
            }
            if (instance == other) {
                return true;
            }
            if (other == null) {
                return false;
            }
            if (!instance.getClass().equals(other.getClass())) {
                return false;
            }
            if (stateAccessors == null) {
                return true;
            }
            return Stream.of(stateAccessors).allMatch(s -> Objects.equals(s.apply(instance), s.apply((T) other)));
        }
    }
    

    For your Person class, using this utility class:

    public boolean equals(Object obj) {
        return Equals.as(this, obj, t -> t.name, t -> t.age);
    }
    

提交回复
热议问题