为什么Collection接口有equals()和hashCode()?

时间:2017-08-11 08:19:45

标签: java collections

为什么Collection界面有{ "settings": { "index": { "analysis": { "filter": { "my_ngram": { "type": "nGram", "min_gram": 1, "max_gram": 50 } }, "char_filter": { "whitespace_mapping": { "mappings": [ "\\u00A0=>\\u0020" ], "type": "mapping" } }, "analyzer": { "default": { "type": "custom", "char_filter": [ "whitespace_mapping" ], "filter": [ "lowercase", "asciifolding", "stop", "my_ngram", "kstem" ], "tokenizer": "whitespace" }, "default_search": { "type": "custom", "char_filter": [ "whitespace_mapping" ], "filter": [ "lowercase", "asciifolding", "kstem" ], "tokenizer": "whitespace" }, "match_phrase": { "type": "custom", "char_filter": [ "whitespace_mapping" ], "filter": [ "lowercase" ], "tokenizer": "whitespace" }, "match_phrase_search": { "type": "custom", "char_filter": [ "whitespace_mapping" ], "filter": [ "lowercase", "stop" ], "tokenizer": "whitespace" } } } } } } equals(Object o),因为默认情况下任何实现都会包含hashCode()

5 个答案:

答案 0 :(得分:5)

来自Collection JavaDoc

  

虽然   Collection接口不对一般合同添加任何规定   对于Object.equals,实施Collection的程序员   界面“直接”(换句话说,创建一个类   Collection但不是SetList)必须小心谨慎   选择覆盖Object.equals。没有必要这样做,   而最简单的行动就是依赖于Object   实施,但实施者可能希望实施“价值   比较“代替默认的”参考比较。“(List   和Set接口要求进行这样的价值比较。)

     

Object.equals方法的一般合同规定等于   必须是对称的(换句话说,a.equals(b)当且仅当   b.equals(a))。 List.equalsSet.equals的合同说明了这一点   列表仅等于其他列表,并设置为其他集。因此,一个   自定义等于不实现的集合类的方法   此集合时,ListSet接口必须返回false   与任何列表或集合相比。 (按照同样的逻辑,不可能   编写一个正确实现Set和List的类   接口。)

  

虽然Collection接口没有为Object.hashCode方法的常规合约添加任何规定,但程序员应注意,任何覆盖Object.equals方法的类也必须覆盖Object.hashCode方法中的Object.hashCode方法。为了满足c1.equals(c2)方法的一般合同。特别是,c1.hashCode()==c2.hashCode()表示 grid-template-columns: repeat(auto-fill,minmax(100px,auto));

答案 1 :(得分:3)

回答您的具体问题:为什么会有这些方法?这样做只是为了方便,能够包含Java Docs,提供实施者应该对这些方法做什么的提示(例如,比较值的相等而不是引用)。

答案 2 :(得分:1)

添加到其他出色的答案中。在Collections接口中,在该接口中定义了equals方法,以使相等于collection的两个实例工作的方式做出一些决策。来自JAVA 8 documentation

  

一般来说,各种馆藏框架的实现   接口可以自由利用以下行为:   实施者认为的基础对象方法   合适的。

因此,您不会出于任何其他原因而从Object类中添加方法,这些原因会使Java文档更具确定性。这就是为什么您不在接口的抽象方法中的抽象方法中计算这些方法的原因。

此外,在JAVA 8中,按照相同的推理,不允许使用Object类的默认方法,它们会产生编译错误。我相信这样做是为了防止此类混淆。因此,例如,如果您尝试创建一个名为hashCode()的默认方法,它将无法编译。

这是Lambda FAQ中对Java 8中此行为的更深入的解释:

  

接口无法为任何   Object类的方法。这是“阶级胜利”的结果   方法解析的规则:在超类链上找到的方法   总是优先于出现在任何   超级接口。特别是,这意味着无法提供默认值   等式,hashCode或toString的实现   界面。

     

乍一看这很奇怪,因为实际上某些接口已定义   他们在文档中的平等行为。 List接口是一个   例。那么,为什么不允许这个呢?

     

一个原因是,对何时进行推理将变得更加困难   调用默认方法。当前的规则很简单:如果一个类   实现一个方法,该方法总是胜过默认实现。   由于接口的所有实例都是Object的子类,因此所有   接口实例具有非默认的equals实现,   hashCode和toString已经。因此,这些的默认版本   在接口上总是无用的,它也可能无法编译。

     

另一个原因是提供了这些的默认实现   接口中的方法很可能会被误导。这些方法   根据对象的状态执行计算,但接口   一般,无法进入国家;只有实施者有   进入此状态。因此,课程本身应提供   实现和默认方法不太可能有用。

答案 3 :(得分:0)

在上述情况下,只需添加“等于”或“ hashCode”方法就可以了:

Collection<Whatever> list1 = getArrayList();
Collection<Whatever> list2 = getAnotherArrayList();

if(list1.equals(list2)){
    // do something
}

如果界面中没有equals方法,我们将被迫使用具体类型,这通常不是一个好习惯:

ArrayList<Whatever> list1 = getArrayList();
ArrayList<Whatever> list2 = getAnotherArrayList();

if(list1.equals(list2)){
    // do something
}

答案 4 :(得分:-1)

当任何类实现接口时,它会注入/接受接口定义的合同/规则。

Equalable&amp; Hashable是两个默认提供的合同/规则。通过这个假设为该类正确实现了给定类的equals和hashCode。