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

时间:2014-06-02 08:15:00

标签: java arraylist equals contains

[以下固定问题]

我有这堂课:

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() {
    ...
  }
}

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

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

它返回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() {
    ...
  }
}

1 个答案:

答案 0 :(得分:6)

您认为contains()会致电memberInCollection.equals(candidate)而不是candidate.equals(memberInCollection)documentation与此相反:

  

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

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

new Doc("123").equals("123") // True
"123".equals(new Doc("123")) // False

(此外,如果equals是对x.equals(x)实例的引用,那么x方法甚至不具有反身性,Doc永远不会成立。)

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