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)在类Test中插入hashCode的重写,如下所示:
public int hashCode() {return size/5};
运行和编译代码表明第一种情况下set的大小是3,而在第二种情况下它是2.
为什么?
在情况1中,虽然equals方法被覆盖,但它永远不会被调用.这是否意味着如果不覆盖hashCode方法,add()方法不会检查对象是否相等?
在情况2中,具有给定实现的hashCode和给定的Test对象集始终返回相同的数字.这与默认的hashCode实现有什么不同,为什么它会导致equals被调用?
解决方法
现在,即使你重写了equals()方法,根据某些属性使两个实例相等,它们的哈希码仍然不同.
因此,具有不同哈希码的两个实例永远不会相等.所以集合的大小是3.因为它没有任何重复.
但是,当您使用以下实现覆盖hashCode()时: –
public int hashCode() {return size/5};
它将返回相同大小的相同值.因此,具有相同大小值的实例将具有相同的哈希码,并且,因为您已根据大小在equals方法中对它们进行比较,因此它们将是相等的,因此它们将在您的Set中被视为重复,因此将被删除.所以,Set.size()是2.
道德: – 每当你重写equals()方法时,你应该总是覆盖hashCode(),以维护两个方法之间的一般契约.
hashcode和equals方法之间的一般契约: –
>当两个对象相等时,它们的哈希码必须相等
>当两个对象不相等时,它们的哈希码可以相等
> hashCode算法应始终为同一对象生成相同的值.
>如果两个对象的hashCode不同,它们将不相等
>始终使用相同的属性来计算用于比较两个实例的hashCode
强烈建议至少阅读一次: –
> Effective Java - Item#9: Always override hashCode when you override equals