Reputation: 93
I know in Java you can't compare two unrelated instances using ==
, since it produces a compilation error (incompatible types). So for example
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
Dog d = new Dog();
Cat c = new Cat();
System.out.println( d == c );
is a compile-time error.
But why doesn't using equals inherited from Object
produce that kind of error:
System.out.println( d.equals(c) ); // is false
even though Object.equals
internally uses ==
?
Now, I know why it's false
, but I don't know why it's not an error, since the signature is:
public boolean equals(Object obj) {
return (this == obj);
}
Upvotes: 2
Views: 1513
Reputation: 21162
The compile time check is performed at the site of the reference equality — within Object.equals
. In the context of the Object.equals
method you referenced, it is comparing this
with an Object
:
public boolean equals(Object obj) {
return (this == obj);
}
Per the Java Language Specification:
It is a compile-time error if it is impossible to convert the type of either operand to the type of the other by a casting conversion (§5.5). The run-time values of the two operands would necessarily be unequal (ignoring the case where both values are
null
).
Since this
can be cast to Object
, this == obj
is a valid usage of the reference equality operator (==
), and therefore it compiles.
For a practical example, observe a case within the Java API where two objects cannot be compared via reference equality (==
), but which are equal when compared via Object.equals
.
First, note that the implementation of Object.equals
is just the base implementation of equals
. Subclasses of Object
are encouraged to use a different implementation, if appropriate.
Second, note that unlike the reference equals operator (==
), the equals
method has no restriction on whether two compared objects can be cast to the type of the other. Per the Javadocs of Object.equals
, the two objects need only implement an equivalence relation:
The
equals
method implements an equivalence relation on non-null object references:
- It is reflexive: for any non-null reference value
x
,x.equals(x)
should returntrue
.- It is symmetric: for any non-null reference values
x
andy
,x.equals(y)
should returntrue
if and only ify.equals(x)
returnstrue
.- It is transitive: for any non-null reference values
x
,y
, andz
, ifx.equals(y)
returnstrue
andy.equals(z)
returnstrue
, thenx.equals(z)
should returntrue
.- It is consistent: for any non-null reference values
x
andy
, multiple invocations ofx.equals(y)
consistently returntrue
or consistently returnfalse
, provided no information used inequals
comparisons on the objects is modified.- For any non-null reference value
x
,x.equals(null)
should returnfalse
.
Take the Java List
interface. It specifies how implementing classes must implement equals:
Compares the specified object with this list for equality. Returns
true
if and only if the specified object is also a list, both lists have the same size, and all corresponding pairs of elements in the two lists are equal. (Two elementse1
ande2
are equal ifObjects.equals(e1, e2)
.) In other words, two lists are defined to be equal if they contain the same elements in the same order. This definition ensures that the equals method works properly across different implementations of theList
interface.
Now, take two lists that can't be cast to one another, such as ArrayList
and LinkedList
. A LinkedList
reference cannot be compared with an ArrayList
reference using the reference equality error (==
), since neither type can be cast to the other. On the other hand, an ArrayList
will be .equals
to a LinkedList
if they contain the same elements in the same order.
ArrayList<String> a = new ArrayList<String>(Arrays.asList("X", "Y", "Z"));
LinkedList<String> b = new LinkedList<String>(Arrays.asList("X", "Y", "Z"));
assert a.equals(b); // true
assert a == b; // compiler error
Upvotes: 0
Reputation: 15105
Because inside Object#equals
the types you compare are both Object
, thus the ==
operator is "allowed".
Remember though that you most of the time don't want to compare using ==
or the default Object#equals
as it compares the references, not the content. See https://stackoverflow.com/questions/7520432/what-is-the-difference-between-and-equals-in-java?r=SearchResults&s=3|156.7237
Upvotes: 2