Java 重写equals方法时违反自反性规则

Java 重写equals方法时违反自反性规则,java,collections,Java,Collections,我对《有效的Java》一书有一个疑问。怀疑是关于equals方法 反身规则违反。书中说: 如果您违反它,然后将类的实例添加到集合中,则集合的contains方法几乎肯定会说集合不包含您刚才添加的实例 为了测试它,我编写了一个示例类,但是contains方法不返回false它返回true。有人能说出问题出在哪里吗?自反意味着x.equals(x)应该返回true class Foo { int i; public boolean equals(Object obj) { r

我对《有效的Java》一书有一个疑问。怀疑是关于equals方法
反身规则违反。书中说:

如果您违反它,然后将类的实例添加到集合中,则集合的contains方法几乎肯定会说集合不包含您刚才添加的实例


为了测试它,我编写了一个示例类,但是contains方法不返回
false
它返回
true
。有人能说出问题出在哪里吗?

自反意味着
x.equals(x)
应该返回
true

class Foo {
   int i;
   public boolean equals(Object obj) {
      return ((Foo) obj).i < this.i;
   }
}
class-Foo{
int i;
公共布尔等于(对象obj){
返回((Foo)obj).i
这将返回
false
。当您将其放入列表并调用
list.contains(foo)
时,它将返回false,因为列表中没有一个元素与您传递的元素相等。这是因为
list.contains(..)
迭代元素,并为每个元素检查
if(elem.equals(arg))


参见

的文件我同意该计划的结果是:

import java.util.*;
类项目{
@凌驾
公共布尔等于(对象obj){
返回false;//甚至不等于它本身。
}
}
课堂测试{
公共静态void main(字符串[]args){
集合项=新的HashSet();
项目i=新项目();
项目.添加(i);
System.out.println(items.contains(i));//打印为真!
}
}
答案是在执行
参数.equals(object)
之前,
包含
实现检查
参数==object
contains
的结果是
true
,因为
item==item
保持不变,即使
item.equals(item)
返回false

假设
等于
遵循其契约
(是自反的),这种实现
包含
的方法是正确的


如果你仔细阅读你发布的引文,作者包含了“几乎”一词:)你似乎偶然发现了这条规则的少数例外之一



其他集合(例如,
ArrayList
)直接使用
equals
,如果在上面的程序中从
newhashset()
更改为
newarraylist()
,它将按预期运行。

当您将其放入列表和调用列表中时。contains(foo)将返回false。。。但对于一般的收藏品来说并非如此:@aioobe-这很有趣。它实际上破坏了
集合
集合
接口定义的契约。(我链接了文档)@Bozho:不,它不会破坏契约,因为契约只适用于那些也不会破坏
equals()
/
hashCode()
契约的对象。示例中的类显然违反了
equals()
契约。这是一种典型的“一文不值”的情况。@Joachim Sauer说它只依赖于
equals(…)
返回的内容,而事实上它并不依赖于
equals(…)
返回的内容。@Bozho:如果
equals()
以符合规范的方式实现,它就会这样做。一般来说,当您使用的对象不符合规范时,什么都不能保证。对于
hashCode()
,情况也是如此:如果您错误地实现了它,那么
HashSet
将异常崩溃。请注意,它给出的代码是规范(必须在围绕它的其他规范的上下文中阅读),而不一定是用于实现它的代码!
import java.util.*;

class Item {
    @Override
    public boolean equals(Object obj) {
        return false;   // not even equal to itself.
    }
}

class Test {
    public static void main(String[] args) {
        Collection<Item> items = new HashSet<Item>();
        Item i = new Item();
        items.add(i);
        System.out.println(items.contains(i));   // Prints true!
    }
}