Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's wrong with using Inheritance Equality in Java?

In the book "Core Java Volume 1" that I am reading it says the equality shouldn't work with inheritance. So, I have the following example which seems to have something wrong going on:

public class Main {

    public static void main(String[] args) {

        C c = new C("Test", 10);
        D d = new D("Test", 10);

        if (c.equals(d))
            System.out.println("Equal");
        else
            System.out.println("Unequal");

        if (d.equals(c))
            System.out.println("Equal");
        else
            System.out.println("Unequal");
    }
}


class C
{
    C(String cstr, int cnum) {
        str = cstr;
        num = cnum;
    }

    @Override
    public boolean equals(Object otherObject) {

        // A quick test to see if the objects are identical.
        if (this == otherObject) {
            return true;
        }

        // Must return false if the explicit parameter is null
        if (otherObject == null)
        {
            return false;
        }

        if (!(otherObject instanceof C))
            return false;

        // Now we know otherObject is a non-null Employee
        C other = (C) otherObject;

        // Test whether the fields have identical values
        return str.equals(other.str) && num == other.num;
    }

    private String str;
    private int num;
}

class D extends C {

    D(String cstr, int cnum) {
        super(cstr, cnum);
    }
}

http://ideone.com/PhFBwG

It returns "Equal" for both symmetrical comparisons which presumably it shouldn't. Is it missing another equals method in derived class 'D'? If so then what could wrong with above sample code if I don't use another equals in derived it at all?

like image 231
cpx Avatar asked Jul 27 '15 13:07

cpx


People also ask

Should I use .equals or == java?

We can use == operators for reference comparison (address comparison) and . equals() method for content comparison. In simple words, == checks if both objects point to the same memory location whereas . equals() evaluates to the comparison of values in the objects.

Where inheritance should not be used in java?

The reason behind this is to prevent ambiguity. Consider a case where class B extends class A and Class C and both class A and C have the same method display(). Now java compiler cannot decide, which display method it should inherit. To prevent such situation, multiple inheritances is not allowed in java.

What does the equals () method is inherited from Object do?

The equals() method compares two objects for equality and returns true if they are equal. The equals() method provided in the Object class uses the identity operator ( == ) to determine whether two objects are equal. For primitive data types, this gives the correct result.


2 Answers

That code works because, as you said, D doesn't override equals. I expect the point the book is making is that D should override equals (and they should both override hashCode), because a D instance shouldn't be equal to a C instance, as they're different (albeit related) types.

Remember that one of the key aspects of the equals contract is symmetry. For any non-null values of c and d, if c.equals(d) is true, then d.equals(c) must be true (and the converse). While that's true in your current code, it probably shouldn't be, because D and C are different types. If a D instance is truly equivalent to a C instance, why have D?

like image 97
T.J. Crowder Avatar answered Oct 20 '22 03:10

T.J. Crowder


If you want instances C and D to not compare as equal replace !(otherObject instanceof C) with otherObject.getClass() != this.getClass(). This would ensure that only a C could ever be equal to another C and only a D could ever be equal to another D.

Whether or not that's what you want depends on a few factors. My general rule of thumb is that it's a bad idea to have an "open-ended" equality class where "external users" (whatever that means for you) can add to it. If you want objects of different types to compare as equal (and that's rare enough), then the hierarchy should be strictly controlled (with final classes, for example).

Collections (and similar well-defined interfaces) are different: here the interface defines a very precise contract that all implementing classes need to follow (i.e. an ArrayList can be equal to a LinkedList if they both contain the same elements in the same order, because the List interface defines what it means for two Lists to be equal).

like image 24
Joachim Sauer Avatar answered Oct 20 '22 05:10

Joachim Sauer