关于重写equals()为什么一定要重写hashcode()自己的一点心得

Bonnie ·
更新时间:2024-09-20
· 587 次阅读

首先我们看下下面代码及输出和String重写equals和hashcode的源码:

package com.zzy.test; public class Test6 { public static void main(String[] args) { String s1="aaa"; String s2="aaa"; String s3=new String("aaa"); String s4="bbb"; System.out.println(s1.equals(s2)); System.out.println(s1.hashCode()+"------"+s2.hashCode()); System.out.println(s1==s2); System.out.println("------------------------------------"); System.out.println(s1.equals(s3)); System.out.println(s1.hashCode()+"------"+s3.hashCode()); System.out.println(s1==s3); System.out.println("------------------------------------"); System.out.println(s1.equals(s4)); System.out.println(s1.hashCode()+"------"+s4.hashCode()); System.out.println(s1==s4); } } output: true 96321------96321 true ------------------------------------ true 96321------96321 false ------------------------------------ false 96321------97314 false public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; } public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }

在写这块代码的时候惊奇的发现String不用导包,原来java.lang包下的内容都是自动就导入的,我竟然现在才发现这个。
首先我们看下s1和s2的比较,equals比较返回true(因为String重写了Object的equals方法,重写后是判断内容相等,之前是判断内存地址是否一样),hashcode值也相等(两者对象本身就相等,hashcode必然相等),比较地址也相等,因为s1 s2 指向是同一个对象“aaa”,“aaa”在第一次创建后会在常量池中,然后s1和s3的比较,首先两者内容和hashcode相等,但是地址是不一样的,这是因为重写equals的时候也重写了hashcode,而如果equals相等hashcode也必须相等,如果只重写了equals不重写hashcode就会导致可能会出现equals相等,但hsahcode不相等的情况。下面我们可以看下一个自定义类只重写equals方法的情况:

package com.zzy.test; import com.zzy.bean.Person; public class Test7 { public static void main(String[] args) { Person person1 = new Person("张三", 18); Person person2 = new Person("张三", 18); System.out.println(person1.equals(person2)); System.out.println(person1.hashCode()+"------"+person2.hashCode()); System.out.println(person1==person2); } } //不重写equals和hashcode时output: false 2125039532------312714112 false //只重写equals时output: true 2125039532------312714112 false //两者都重写时output: true 24022538------24022538 false

可以很清楚看出三种情况的区别,有的人可能会问为什么equals相等要保证hashcode相等呢
如果内容相等而hashcode不等,在使用散列数据结构(HashSet,HashMap,LinkedHashSet或LinkedHashMap)时就会出现问题,由于散列表中桶位的下标是hashcode经过一些处理以及根据容器的程度和负载因子来生成的,这样就会导致插入两个内容相同的key可能会出现不覆盖的情况,代码举例如下:

package com.zzy.test; import com.zzy.bean.Person; import java.util.HashMap; public class Test7 { public static void main(String[] args) { Person person1 = new Person("张三", 18); Person person2 = new Person("张三", 18); HashMap map = new HashMap(); map.put(person1,3); System.out.println(map.get(person1)); map.put(person2,4); System.out.println(map.get(person2)); System.out.println(map.get(person1)); } } //只重写equals时output: 3 4 3 //两者都重写时output: 3 4 4

可以看到只重写equals的时候put两个内容相同的key不会覆盖,两者都重写才会覆盖。这就是为什么要重写equals的时候也要重写hashcode了。

以上就是我关于为什么要重写equals的时候也要重写hashcode的一些心得,大家如果觉得看了对自己有所帮助,还望能点个关注点个赞,感谢


作者:树荫下的蚂蚁



equals hashcode

需要 登录 后方可回复, 如果你还没有账号请 注册新账号