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?
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.
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.
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.
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
?
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 List
s to be equal).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With