当覆盖等于方法时违反反身性规则

yag*_*nya 4 java collections

我对Efective Java这本书有所怀疑.怀疑是关于equals方法
反身规则违反.这本书说如下:

" 如果你违反了它,然后将你的类的一个实例添加到一个集合中,那么集合的contains方法肯定会说该集合不包含你刚刚添加的实例. "

为了测试它,我写了一个示例类,但contains方法没有返回false它返回true.谁能说出问题是什么?

aio*_*obe 6

我同意这个程序的结果确实令人费解:

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!
    }
}
Run Code Online (Sandbox Code Playgroud)

答案是在contains执行argument == object之前执行检查argument.equals(object).从结果containstrue,因为item == item持有,即使item.equals(item)返回false.

假设equals遵循其合同(反身),这种实施方式contains是正确的.


如果你仔细阅读了你发布的引用,那么作者就会包含" 几乎 " 这个词 :)你似乎偶然发现了该规则的少数例外情况之一.


其他集合(ArrayList例如)equals直接使用,如果在上面的程序中更改new HashSet<Item>()new ArrayList<Item>(),则按false预期打印.


Boz*_*zho 5

反身手段x.equals(x)应该回来true

class Foo {
   int i;
   public boolean equals(Object obj) {
      return ((Foo) obj).i < this.i;
   }
}
Run Code Online (Sandbox Code Playgroud)

这将返回false。当您将其放入列表并调用list.contains(foo)它时,它将返回false,因为列表中的所有元素都不等于您传递的元素。之所以这样,是因为list.contains(..)对元素进行了迭代,并对每个元素进行检查if (elem.equals(arg))

请参阅的文档 Collection.contains(..)