首先我们看下下面代码及输出和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<Person, Integer> map = new HashMap<Person, Integer>();
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的一些心得,大家如果觉得看了对自己有所帮助,还望能点个关注点个赞,感谢