简体   繁体   中英

Why does the Collection interface have equals() and hashCode()?

为什么Collection接口有equals(Object o)hashCode() ,因为默认情况下任何实现都会有这些(继承自Object )?

From the Collection JavaDoc :

While the Collection interface adds no stipulations to the general contract for the Object.equals , programmers who implement the Collection interface "directly" (in other words, create a class that is a Collection but is not a Set or a List ) must exercise care if they choose to override the Object.equals . It is not necessary to do so, and the simplest course of action is to rely on Object's implementation, but the implementor may wish to implement a "value comparison" in place of the default "reference comparison." (The List and Set interfaces mandate such value comparisons.)

The general contract for the Object.equals method states that equals must be symmetric (in other words, a.equals(b) if and only if b.equals(a) ). The contracts for List.equals and Set.equals state that lists are only equal to other lists, and sets to other sets. Thus, a custom equals method for a collection class that implements neither the List nor Set interface must return false when this collection is compared to any list or set. (By the same logic, it is not possible to write a class that correctly implements both the Set and List interfaces.)

and

While the Collection interface adds no stipulations to the general contract for the Object.hashCode method, programmers should take note that any class that overrides the Object.equals method must also override the Object.hashCode method in order to satisfy the general contract for the Object.hashCode method. In particular, c1.equals(c2) implies that c1.hashCode()==c2.hashCode() .

To answer your specific question: why does it have these methods? It's done simply for convenience to be able to include Java Docs giving hints as to what implementers should do with these methods (eg comparing equality of values rather than references).

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
}

Equals and hashCode method help to compare objects. Collection interface works on different object in-order to compare them or in-order to check duplicates equals and hashcode will be used.

Equalable & Hashable are two default provided contracts/rules. By having this It's assumed that equals and hashCode for a given class are implemented correctly for that class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM