为什么这= = other和this.hashcode == other.hashcode()给出不同的结果?

时间:2014-12-24 01:48:18

标签: java equals

我的课程包含以下equals()hashCode()方法

@Override
public boolean equals(Object o)
{
  if (this == o) { return true; }
  if (o == null || getClass() != o.getClass()) { return false; }

  Phrases that = (Phrases) o;

  if (this.hashCode() == o.hashCode()) { return true; } //retry clover coverage test
  if (exitMsg != null ? !exitMsg.equals(that.exitMsg) : that.exitMsg != null)
  { return false; }
  if (introMsg != null ? !introMsg.equals(that.introMsg) : that.introMsg != null)
  { return false; }
  if (msg != null ? !msg.equals(that.msg) : that.msg != null)
  { return false; }
  if (phrase != null ? !phrase.equals(that.phrase) : that.phrase != null)
  { return false; }
  if (title != null ? !title.equals(that.title) : that.title != null)
  { return false; }

  return true;
}

@Override
public int hashCode()
{
  int result = phrase != null ? phrase.hashCode() : 0;
  result = 31 * result + (title != null ? title.hashCode() : 0);
  result = 31 * result + (introMsg != null ? introMsg.hashCode() : 0);
  result = 31 * result + (msg != null ? msg.hashCode() : 0);
  result = 31 * result + (exitMsg != null ? exitMsg.hashCode() : 0);
  return result;
}

我试图找出为什么 clover 无法告诉我的哈希码方法已经运行。我添加了一行:

if (this.hashCode() == o.hashCode()) { return true; } //retry clover coverage test

根据三叶草每次等于方法运行if (this == o) { return true; } false if (this.hashCode() == o.hashCode()) { return true; } true


问题:

为什么this == othis.hashCode() == o.hashCode()没有评估相同的结果?

3 个答案:

答案 0 :(得分:5)

根据定义,哈希码包含的信息少于源数据。这意味着碰撞是可能的,在这种情况下,您将拥有两个具有相同哈希码但不相等的对象。

Java hashCode()的一般要求是相反的方向:

  • equals关系所持有的两个对象必须生成相同的哈希码(相反的情况并非如此)
  • 如果两个对象不同,则不需要生成不同的哈希码

基本上关键是你不能将哈希码用作唯一标识符(事实上JDK数据结构在内部管理冲突)。

这与==没有任何关系,因为它只比较了对象的引用(内存地址),hashCode()和equals将完全相同。

如果你看看你的hashCode(),你可以看到,如果除了一个字段之外的所有字段都为空,但是哪个字段不同,则计算的哈希码是相同的,这清楚地证明了你可以轻松地产生碰撞。

如果你想要更强大的东西,你应该考虑使用MessageDigest,它产生的摘要比int长得多(因此能够容纳更多信息=不太可能发生碰撞)。但即使有他们也不会有任何保证。

答案 1 :(得分:0)

==不会致电.equals

实际上,两者完全不同,仅在未覆盖Object的默认(不良)实现的对象中重叠。

==只是检查太多的对象是否是等效的指针。

.equals会运行与您展示的方法类似的方法。

==替换.equals可以解决您的问题

答案 2 :(得分:0)

退一步......

考虑equals()hashCode()的合同。考虑一下合同只是单向的事实:如果你在一个类中实现两者,那么要求是如果一个类的两个实例相等,那么它们必须具有相同的哈希码。

它没有说的是,如果两个实例具有相同的哈希码,那么它们必须相等。但是你假设你的.equals()实现了!

然而在你的代码中,有:

// WRONG!
if (this.hashCode() == o.hashCode()) { return true; }

以下是一个完全有效的hashCode()方法示例:

public int hashCode()
{
    return 42;
}

现在,我相信您可以通过.equals()方法查看问题所在......


假设Java 7,这里是你编写这两种方法的方法;因为两者都占null,所以这很容易(另一方面,你应该尽可能避免使用null;最终,null只不过是麻烦了):

@Override
public final int hashCode()
{
    return Objects.hash(phrase, title, introMsg, msg, errorMsg);
}

@Override
public final boolean equals(final Object obj)
{
    if (obj == null)
        return false;
    if (this == obj)
        return true;
    if (getClass() != obj.getClass())
        return false;
    final MyClass other = (MyClass) obj;
    return Objects.equals(phrase, other.phrase)
        && Objects.equals(title, other.title)
        && Objects.equals(introMsg, other.introMsg)
        && Objects.equals(msg, other.msg)
        && Objects.equals(errorMsg, other.errorMsg);
}