Java 重写equals方法时违反自反性规则
我对《有效的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
反身规则违反。书中说: 如果您违反它,然后将类的实例添加到集合中,则集合的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!
}
}