Overriding equals() & hashCode() in sub classes … considering super fields

前端 未结 10 1214
一个人的身影
一个人的身影 2020-12-07 13:19

Is there a specific rule on how Overriding equals() & hashCode() in sub classes considering super fields ?? k

相关标签:
10条回答
  • 2020-12-07 13:51

    Well, HomoSapiens#hashcode will be enough with CPerkins's answer.

    @Override     
    public int hashCode() {     
        int hash = super.hashCode();
        hash = 89 * hash + Objects.hash(name);     
        hash = 89 * hash + Objects.hash(faceBookNickname);     
        return hash;     
    }
    

    If you want those parent's fields(gender, weight, height) in action, one way is creating an actual instance of parent type and use it. Thank God, it's not an abstract class.

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final HomoSapiens other = (HomoSapiens) obj;
        if (!super.equals(new Hominidae(
            other.gender, other.weight, other.height))) {
             return false;
        }
        if (!Objects.equals(name, other.name)) return false;
        if (!Objects.equals(faceBookNickname, other.faceBookNickname))
            return false;
        return true;
    }
    

    I'm adding a way to (I think) solve this. The key point is adding a method loosely checks the equality.

    public class Parent {
    
        public Parent(final String name) {
            super(); this.name = name;
        }
    
        @Override
        public int hashCode() {
            return hash = 53 * 7 + Objects.hashCode(name);
        }
    
        @Override
        public boolean equals(final Object obj) {
            return equalsAs(obj) && getClass() == obj.getClass();
        }
    
        protected boolean equalsAs(final Object obj) {
            if (this == obj) return true;
            if (obj == null) return false;
            if (!getClass().isAssignableFrom(obj.getClass())) return false;
            final Parent other = (Parent) obj;
            if (!Objects.equals(name, other.name)) return false;
            return true;
        }
    
        private final String name;
    }
    

    And here comes the Child.

    public class Child extends Parent {
    
        public Child(final String name, final int age) {
            super(name); this.age = age;
        }
    
        @Override
        public int hashCode() {
            return hash = 31 * super.hashCode() + age;
        }
    
        @Override
        public boolean equals(final Object obj) {
            return super.equals(obj);
        }
    
        @Override
        protected boolean equalsAs(final Object obj) {
            if (!super.equalsAs(obj)) return false;
            if (!getClass().isAssignableFrom(obj.getClass())) return false;
            final Child other = (Child) obj;
            if (age != other.age) return false;
            return true;
        }
    
        private final int age;
    }
    

    Testing...

    @Test(invocationCount = 128)
    public void assertReflective() {
        final String name = current().nextBoolean() ? "null" : null;
        final int age = current().nextInt();
        final Child x = new Child(name, age);
        assertTrue(x.equals(x));
        assertEquals(x.hashCode(), x.hashCode());
    }
    
    @Test(invocationCount = 128)
    public void assertSymmetric() {
        final String name = current().nextBoolean() ? "null" : null;
        final int age = current().nextInt();
        final Child x = new Child(name, age);
        final Child y = new Child(name, age);
        assertTrue(x.equals(y));
        assertEquals(x.hashCode(), y.hashCode());
        assertTrue(y.equals(x));
        assertEquals(y.hashCode(), x.hashCode());
    }
    
    @Test(invocationCount = 128)
    public void assertTransitive() {
        final String name = current().nextBoolean() ? "null" : null;
        final int age = current().nextInt();
        final Child x = new Child(name, age);
        final Child y = new Child(name, age);
        final Child z = new Child(name, age);
        assertTrue(x.equals(y));
        assertEquals(x.hashCode(), y.hashCode());
        assertTrue(y.equals(z));
        assertEquals(y.hashCode(), z.hashCode());
        assertTrue(x.equals(z));
        assertEquals(x.hashCode(), z.hashCode());
    }
    
    0 讨论(0)
  • 2020-12-07 13:56

    The rules are:

    • It is reflexive: for any non-null reference value x, x.equals(x) should return true.
    • It is symmetric: for any non-null reference 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 reference 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 reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
    • For any non-null reference value x, x.equals(null) should return false.
    • Is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes

    from Object.equals().

    So, use the fields needed to fulfill the rules.

    0 讨论(0)
  • 2020-12-07 13:56

    I believe they now have a method that just does this for you :

    EqualsBuilder.reflectionEquals(this, o);

    HashCodeBuilder.reflectionHashCode(this);

    0 讨论(0)
  • 2020-12-07 14:00

    It's worth noting that the IDE auto generation maybe has taken into consideration super class,just provided that the equals() and hashCode() of super class exists yet. That is, should auto generate these two functions of super first, and then auto generate of the child. I got below right example under Intellj Idea:

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        if (!super.equals(o)) return false;
    
        TActivityWrapper that = (TActivityWrapper) o;
    
        return data != null ? data.equals(that.data) : that.data == null;
    }
    
    @Override
    public int hashCode() {
        int result = super.hashCode();
        result = 31 * result + (data != null ? data.hashCode() : 0);
        return result;
    }
    

    The problem happens just when you don't auto generate super's in first. Please check above under Netbeans.

    0 讨论(0)
提交回复
热议问题