Generally speaking, although it is not strictly expressed in the contract for equals(), objects should not consider themselves equal to another object that is not of the exact same class (even if it is a subclass). Consider the symmetric property - if a.equals(b) is true, then b.equals(a) must also be true.
Let's have two objects, foo
of class Super
, and bar
of class Sub
, which extends Super
. Now consider the implementation of equals()
in Super, specifically when it's called as foo.equals(bar)
. Foo only knows that bar is strongly typed as an Object
, so to get an accurate comparison it needs to check it's an instance of Super and if not return false. It is, so this part is fine. It now compares all the instance fields, etc. (or whatever the actual comparison implementation is), and finds them equal. So far, so good.
However, by the contract it can only return true if it know that bar.equals(foo) is going to return true as well. Since bar can be any subclass of Super, it's not clear whether the equals() method is going to be overridden (and if probably will be). Thus to be sure that your implementation is correct, you need to write it symmetrically and ensure that the two objects are the same class.
More fundamentally, objects of different classes cannot really be considered equal - since in this case, only one of them can be inserted into a HashSet<Sub>
, for example.