当equals(Object o)返回true时,使用contains(Object o)比较两个不同的对象将返回false

ipo*_*oga 1 java contains equals arraylist

[下面的固定问题]

我有这门课:

Class Doc() {
  private String D;

  Doc(String d) {
    D = d;
  }

  @Override
  public boolean equals(Object o) {
    if (o instanceOf String) {
      if (o.equals(D)) return true;
      else return false;
    } else return false;
  }

  @Override
  public int hashCode() {
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

如果我运行测试,使用例如"abc"作为参数启动Doc()然后使用Doc().equals("abc")它返回true - 正如我所料.如果我使用:

ArrayList docs = new ArrayList<Doc>();
Doc d = new Doc("123");
Docs.add(d);
System.out.println(docs.contains("123"));
Run Code Online (Sandbox Code Playgroud)

它返回false,我不确定为什么.我已经尝试将输出添加到.equals()方法以检查它是否被使用,它是.这个代码hashCode()只是一些虚假(我知道我应该做一些正确的事,我只是不确定如何) - 但我只会使用equals().

不过,我读到的地方equals()也会检查hashCode(); 如果我在其中添加System.out.println(".")第一行hashCode()并不输出任何内容,那么它似乎不会被调用.我最好的猜测是我无法比较不同类的两个对象 - 这是正确的吗?还是我忽略了别的什么?


为了将来参考,使用@JonSkeet的建议解决了这个问题 - 代码现在是:

Class Doc() {
  private String D;
  Doc(String d) {
    D = d;
  }

  public String getD() {
    return D;
  }

  @Override
  public boolean equals(Object o) {
    if (o instanceOf Doc) {
      Doc tmp = (Doc) o;
      if (tmp.getD().equals(D)) return true;
      else return false;
    } else return false;
  }

  @Override
  public int hashCode() {
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 6

你假设contains()会打电话memberInCollection.equals(candidate)而不是打电话candidate.equals(memberInCollection).该文件违背认为:

更正式地说,当且仅当此列表包含至少一个元素e时才返回true (o==null ? e==null : o.equals(e)).

从根本上说,你的equals方法打破了正常的契约,因为它不是对称的 - 对于任何非空值的xy,x.equals(y) == y.equals(x)应该是真的.这是不是你的代码的情况下:

new Doc("123").equals("123") // True
"123".equals(new Doc("123")) // False
Run Code Online (Sandbox Code Playgroud)

(此外,您的equals方法甚至不是自反的 - x.equals(x)如果x是对实例的引用,则永远不会为真Doc.)

基本上,您不应该尝试使一个类型的实例等于不相关类型的实例.它总会很糟糕.在类型层次结构中使得平等很好地工作是很困难的 - 但对于不相关的类型,这是一个非常糟糕的主意.