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

时间:2011-08-02 08:46:17

标签: java collections

我对“Efective Java”一书表示怀疑。怀疑是关于平等方法
反身规则违规。这本书说明如下:

  

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

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

2 个答案:

答案 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))

请参阅Collection.contains(..)

的文档