java LinkedHashSet

时间:2012-10-21 19:51:18

标签: java hash scjp linkedhashset

我一直在为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?

2 个答案:

答案 0 :(得分:10)

如果您不覆盖hashCode(),那么您的每个实例都会根据{{1}中的某些预定义哈希算法计算出哈希码 }类。因此,您的所有实例都可能具有不同的哈希码值(但这不是必须的)。意味着,每个实例都将进入自己的

现在,即使您重写了Object方法,根据某些属性使两个实例相等,它们的哈希码仍然不同。

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


但是,当您通过以下实施覆盖equals()时: -

hashCode()

它将为同一public int hashCode() {return size/5}; 返回相同的值。因此,具有相同值size的实例将具有相同的哈希码,并且,因为您已基于sizeequals方法中对它们进行了比较,因此它们是将是size,因此它们将在equal中被视为重复,因此将被删除。因此,Set为2。

道德: - 每当覆盖Set.size()方法时,都应该覆盖hashCode(),以维持两种方法之间的一般契约。

equals()hashcode方法之间的一般合​​同: -

  • 当两个对象相等时,它们的哈希码必须相等
  • 当两个对象不相等时,它们的哈希码可以相等
  • hashCode算法应始终为同一对象生成相同的值。
  • 如果两个对象的hashCode不同,则它们将不相等
  • 始终使用equals来计算用于比较两个实例的same attributes

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

答案 1 :(得分:2)

哈希结构依赖于哈希算法,该算法在java中由hashCode()表示。当您将某些内容放入HashMap(或者LinkedHashSet中)时,jvm会对插入此结构的对象调用hashCode()。当它没有被覆盖时,将使用来自hashCode()类的默认Object并且效率低 - 所有对象都进入它们自己的桶中。

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