6

我一直在为 OCJP(前 SCJP)学习,我遇到了以下使用 LinkedHashSet 的示例:

public class Test{

    int size;

    public Test(int s){
       this.size = s;
    }

    @Override
    public boolean equals(Object obj) {
         return (this.size == ((Test)obj).size);
    }

    public static void main(String[] args) {
      LinkedHashSet<Test> s = new LinkedHashSet<Test>();
      s.add(new Test(1));
      s.add(new Test(2));
      s.add(new Test(1));
      System.out.println(s.size());
    }
}

现在,问题是在以下情况下显示什么:
1) 实现保持不变
2) hashCode 的覆盖被插入到类 Test 中,如下所示:

public int hashCode() {return size/5};

运行和编译代码表明,第一种情况下 set 的大小是 3,而第二种情况下是 2。为什么?

在情况 1 中,虽然 equals 方法被覆盖,但它永远不会被调用。这是否意味着如果 hashCode 方法没有被覆盖, add() 方法不会检查对象是否相等?
在情况 2 中,具有给定实现的 hashCode 和给定的 Test 对象集总是返回相同的数字。这与默认的 hashCode 实现有什么不同,为什么会导致 equals 被调用?

4

2 回答 2

10

如果您不覆盖hashCode(),那么您的每个实例都将具有从类中一些预定义的散列算法计算散列Object。因此,您的所有实例都可能具有不同的哈希码值(虽然这不确定)。意味着,每个实例都将进入自己的bucket

现在,即使您重写equals()的方法基于某些属性使两个实例相等,它们的哈希码仍然不同。

因此,具有不同哈希码的两个实例永远不会相等。所以集合的大小是 3。因为它没有任何重复。


但是,当您hashCode()使用以下实现覆盖时:-

public int hashCode() {return size/5};

它将为 same 返回相同的值size。因此,具有相同值的实例将size具有相同的哈希码,并且由于您已经在方法中equals基于sizeequalSetSet.size()

道德hashCode(): -每当您覆盖方法时,您应该始终覆盖equals(),以维护两种方法之间的一般合​​同。

hashcodeequals方法之间的一般合​​同:-

  • 当两个对象相等时,它们的hashcode必须相等
  • 当两个对象不相等时,它们的hashcode可以相等
  • hashCode 算法应该始终为同一个对象生成相同的值。
  • 如果两个对象的 hashCode 不同,它们将不相等
  • 总是same attributes用来计算hashCode你用来比较两个实例的

强烈建议至少阅读一次:-

于 2012-10-21T19:55:22.607 回答
2

散列结构依赖于hashCode()在 java 中表示的散列算法。当您将某些东西放入HashMap(或LinkedHashSet在您的情况下)时,jvm 会调用hashCode()正在插入此结构中的对象。当它没有被覆盖时,将使用类中的默认值,而且效率很低——所有对象都进入它们自己的存储桶hashCode()Object

当您覆盖hashCode()示例中显示的方式时,示例中的所有对象都将进入同一个存储桶。然后(当一个接一个添加它们时),与 进行比较equals()。这就是为什么在第一种情况下(当equals()不调用时)你得到 3 的大小,而在第二种情况下 - 2。

于 2012-10-21T19:57:00.913 回答