我对“Efective Java”一书表示怀疑。怀疑是关于平等方法
反身规则违规。这本书说明如下:
“如果您违反了它,然后将类的实例添加到集合中,则集合的contains方法几乎肯定会说该集合不包含您刚刚添加的实例。 “
为了测试它,我编写了一个示例类,但contains方法没有返回false
它返回true
。谁能说出问题是什么?
答案 0 :(得分:6)
我同意此计划的结果为indeed puzzling:
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!
}
}
答案是contains
实施在执行argument == object
之前检查argument.equals(object)
。自contains
成立以来,true
的结果为item == item
,即使item.equals(item)
返回false。
假设equals
遵循合同(反身),这种实施contains
的方式是正确的。
如果你仔细阅读了你发布的引用,作者包含“几乎”这个词 :)似乎你偶然发现了该规则的少数例外情况之一。
其他集合(例如ArrayList
)直接使用equals
,如果您在上述程序中从new HashSet<Item>()
更改为new ArrayList<Item>()
,则prints false
按预期方式使用{{1}}
答案 1 :(得分:5)
自反意味着x.equals(x)
应该返回true
class Foo {
int i;
public boolean equals(Object obj) {
return ((Foo) obj).i < this.i;
}
}
这将返回false
。当你把它放入一个列表并调用list.contains(foo)
时,它将返回false,因为列表中的所有元素都不等于你传递的元素。之所以如此,是因为list.contains(..)
会迭代元素,并且每个元素都会检查if (elem.equals(arg))