Why does the Collection interface have equals(Object o) and hashCode(), given that any implementation will have those by default (inherited from Object) ?
Why does the Collection interface have equals(Object o) and hashCode(), given that any implementation will have those by default (inherited from Object) ?
To add to the other great answers. In the Collections interface, the equals method is defined in that interface to make some decisions in the way equaling two instances of collection should work. From the JAVA 8 documentation:
More generally, implementations of the various Collections Framework interfaces are free to take advantage of the specified behavior of underlying Object methods wherever the implementor deems it appropriate.
So you don’t add methods from the Object class for any other reason that giving more definitiveness to the java doc. This is the reason why you don’t count those methods in the abstract methods in the abstract methods of an interface.
Moreover, in JAVA 8, along the same line of reasoning, default methods from the Object class are not allowed and will generate a compile error. I believe it’s was done to prevent this type of confusion. So if you try to create a default method called hashCode(), for example, it will not compile.
Here is a more in-depth explanation for this behavior in JAVA 8 from the Lambda FAQ:
An interface cannot provide a default implementation for any of the methods of the Object class. This is a consequence of the “class wins” rule for method resolution: a method found on the superclass chain always takes precedence over any default methods that appear in any superinterface. In particular, this means one cannot provide a default implementation for equals, hashCode, or toString from within an interface.
This seems odd at first, given that some interfaces actually define their equals behavior in documentation. The List interface is an example. So, why not allow this?
One reason is that it would become more difficult to reason about when a default method is invoked. The current rules are simple: if a class implements a method, that always wins over a default implementation. Since all instances of interfaces are subclasses of Object, all instances of interfaces have non-default implementations of equals, hashCode, and toString already. Therefore, a default version of these on an interface is always useless, and it may as well not compile.
Another reason is that providing default implementations of these methods in an interface is most likely misguided. These methods perform computations over the object’s state, but the interface, in general, has no access to state; only the implementing class has access to this state. Therefore, the class itself should provide the implementations, and default methods are unlikely to be useful.
Just to add to the great answers above, it makes sense to have the 'equals' or `hashCode' methods in this scenario:
Collection<Whatever> list1 = getArrayList();
Collection<Whatever> list2 = getAnotherArrayList();
if(list1.equals(list2)){
// do something
}
In the absence of the equals method in the interface, we'll be forced to use concrete types, which is generally not a good practice :
ArrayList<Whatever> list1 = getArrayList();
ArrayList<Whatever> list2 = getAnotherArrayList();
if(list1.equals(list2)){
// do something
}