ArrayList包含的方法不能像我期望的那样工作?

Ali*_*Ali 1 java arraylist

ArrayList equals()在其contains方法中使用,以查看提供对象是否等于列表中的任何项目,如文档所示:

如果此列表包含指定的元素,则返回true.更正式地,当且仅当此列表包含至少一个元素e时才返回true(o == null?e == null:o.equals(e)).看到这个

我有这门课

class Foo
{
  private String value;
  public Foo(String value)
  {
    this.value = value;
  }

  @Override
  public boolean equals(Object o)
  {
    return o == null ? this.value == null : o.toString().equals(this.value);
  }
}
Run Code Online (Sandbox Code Playgroud)

我想用contains方法检查项目是否存在这样

List<Foo> list = new ArrayList<Foo>();

Foo item1 = new Foo("item1");
Foo item2 = new Foo("item2");
list.add(item1);
list.add(item2);

System.out.println(item1.equals("item1"));       //return true
System.out.println(list.contains("item1"));      //false !! why?!
Run Code Online (Sandbox Code Playgroud)

contains方法返回false,而item1.equals("item1")返回true.

为什么contains在使用equals提供对象的方法时返回false

dav*_*xxx 6

您的equals()实施违反了对称原则:

它是对称的:对于任何非空引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)才应返回true.

item1.equals("item1") 回报 true

"item1".equals(item1)回报false.

所以你不应该期望这种Collection方法contains()能够以一致的方式工作.

作为一般规则,equals()重写不应该尝试与其他类互操作,而只应与底层类的实例互操作.

在您的情况下,它仅适用于String传递给方法的参数.
你应该使它适用于Foo实例参数:

  @Override
  public boolean equals(Object o) {
     if (!(o instanceof Foo){ 
       return false;
     }
     Foo other = (Foo) o;
     return Objects.equals(other.value, this.value);
  }
Run Code Online (Sandbox Code Playgroud)


sap*_*ler 5

看看这里的文档,contains将在字符串"item1"上使用equals方法,而不在item1上使用equals方法.例如

"item1".equals(item1)
Run Code Online (Sandbox Code Playgroud)

并不是

item1.equals("item1")
Run Code Online (Sandbox Code Playgroud)

你可以list.contains(new Foo("item1"))改用.


Mic*_*ael 5

你的问题是你的平等不对称.Foo == String并不意味着String == Foo.

如果你看一下你的实现,ArrayList.contains就会看到它的调用objectToFind.equals(objectInList),这可能与你的期望相反:

o.equals(elementData[i])
Run Code Online (Sandbox Code Playgroud)

所以在你的情况下String.equals(Foo).因为String.equals对于不是String的任何内容将返回false,ArrayList.contains返回false.