PerKins Zhu

Le vent se lève,il faut tenter de vivre.

导航

为什么覆写equals必须要覆写hashCode?

Posted on 2017-07-19 22:28  PerKins.Zhu  阅读(1029)  评论(0编辑  收藏  举报

=============================================

原文链接: 为什么覆写equals必须要覆写hashCode? 转载请注明出处!

=============================================

《Effective java》Chapter Three  Item 9:Always override hashCode when you overried equals. (下载链接: Effective_java(英文版)第二版.pdf

 1、 在Object中有两个方法:

public native int hashCode(); 
public boolean equals(Object obj) {
  return (this == obj);//默认比较引用相等
}

 所以任何一个对象都有默认的hashCode()和equals()方法。

 2、在hash表中,hashCode()方法是参与取/存值运算的。

     例如: 

//HashTabel
if ((e.hash == hash) && e.key.equals(key)) {
     return (V)e.value;
}
//HashMap
 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
     return e;

    由此可见,在根据key取value的时候,key相等的必要条件就是两者hashCode相等。

    再说为什么覆写equals必须要覆写hashCode?注意:研究的对象是同一个类的两个不同对象(引用不同)

   先看一段代码:

    @Test
    public void testHashCode(){
        Student stu1 = new Student("JACK");
        Student stu2 = new Student("JACK");
        System.out.println(stu1.equals(stu2));//equal返回true
        System.out.println(stu1.hashCode()+"----"+stu2.hashCode());//hashCode 结果不同。由于Student未覆写hashCode方法,在计算的时候使用的是的Object.hashCode(),计算出来两者的hashCode不一致
        HashMap map = new HashMap();
        map.put(stu1,"123456");
        System.out.println(map.get(stu2));//(逻辑上)本想取出“123456”,但hashMap在取值的时候把两者的hashCode加入比较,因此找不到相等的key值,所以取出结果为null
        
    }
    class Student {
        private String name;
        public Student(String name){
            this.name = name;
        }
        @Override
        public boolean equals(Object obj) {
            //逻辑上名字相等便认为两者相等并不是把引用相等作为判等条件
            return this.name.equals(((Student)obj).name);
        }
    }

 

 运行结果如下:

true
668849042----434176574
null

 

 由这段代码可以看出:在执行map.get(stu2)的时候,程序会获取stu2的hashCode。而Student未覆写hashCode(),所以直接使用父类Object.hashCode()计算hash值,而由于Object.hashCode()返回的stu1和stu2的hash值并不相同,因此,map中未找到stu2对应的key值,所以返回的value便为null。

而示例程序中,本想根据名字相等来判断对象相等获取value值“123456”,可由于调用hashCode()的返回值不同导致最终未取得想要的值。那么解决办法是什么?让stu1.hashCode() == stu2.hashCode()。那么该如何实现? 自定义(覆写)hashCode()方法。

 所以如果自定义了equals()方法,且返回true的充要条件不是(this == obj),那么就必须覆写hashCode,且必须保证equals为true的时候两者的hashCode必须相等,否则当该对象作为key值存在hash表中的时候,就无法用逻辑上相等的对象取出该key所对应的value(如示例)。

Object specification:

Object specification [JavaSE6]:
• Whenever it is invoked on the same object more than once during an execution of an application, the hashCode method must consistently return the same integer, provided no information 
  used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application. • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result. • It is not required that
if two objects are unequal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results.
  However, the programmer should be aware that producing distinct integer results
for unequal objects may improve the performance of hash tables.

 

----end