java 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)在类Test中插入hashCode的重写,如下所示:

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

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

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

解决方法

如果不覆盖hashCode(),那么每个实例都将具有根据Object类中的一些预定义哈希算法计算的哈希码.因此,您的所有实例都可能具有不同的哈希码值(尽管这不是确定的).手段,每个实例都会进入自己的桶.

现在,即使你重写了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

相关文章

最近看了一下学习资料,感觉进制转换其实还是挺有意思的,尤...
/*HashSet 基本操作 * --set:元素是无序的,存入和取出顺序不...
/*list 基本操作 * * List a=new List(); * 增 * a.add(inde...
/* * 内部类 * */ 1 class OutClass{ 2 //定义外部类的成员变...
集合的操作Iterator、Collection、Set和HashSet关系Iterator...
接口中常量的修饰关键字:public,static,final(常量)函数...