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 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
.
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 elements e1
and e2
are equal if Objects.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 the List
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