很多小白在接触java时都会存在一个疑问为什么重新equals方法一定要重新hashcode,废话不多说,我们开始讲解!
为什么需要重新equals方法?
重新equals方法主要时根据一些具体业务有关系,我们现在简单举例假设有一个User类包含了name和age属性。
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
}
针对上述User类,我们尝试创建两个属性相同的对象来判断是否相等!
public class main {
public static void main(String[] args){
User u1 = new User("zhangsan", 123);
User u2 = new User("zhangsan", 123);
System.out.println(u1.equals(u2));
}
}
结果会是什么呢?会是false!Java 中的 equals
方法是比较对象的引用是否相等,而不是对象的内容。因此,当你调用 equals
方法比较 u1
和 u2
时,实际上是在比较两个对象的引用地址,而不是比较它们的属性值。当然如果是基本类型肯定直接比较值了,可惜u1和u2是引用类型!
所以为了让u1和u2属性值相同,就相等,我们就需要重写equals方法!具体如下:
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (this==obj) return true;
if (obj==null||this.getClass()!=obj.getClass()) return false;
User u1 = (User) obj;
return this.age== u1.age&& Objects.equals(this.name,u1.name);
}
}
hashcode方法有什么用?
hashCode 翻译为中文是散列码,它是由对象推导出的一个整型值,并且这个值为任意整数,包括正数或负数。
需要注意的是:散列码是没有规律的。如果 x 和 y 是两个不同的对象,x.hashCode() 与 y.hashCode() 基本上不会相同;但如果 a 和 b 相等,则 a.hashCode() 一定等于 b.hashCode()。
为什么重写equals也要重写hashcode?
以Set集合为例,Set集合不能存储重复元素。什么样的元素是重复元素?它是按照下述方法进行判定的!!!先判断两个对象的hashcode是否相同,如果相同说明在哈希表的位置是一样的【因为hashcode作用是确定对象在hash表中的位置】,判断出一个位置相同后再进行equals进行比对内存地址是否相等。如果hashcode相同且equals也相同则是重复元素则会去重!。
下面还是以刚才的u1和u2对象为例子,我们已经知道了u1和u2重写了equals方法,但是没有重写hashcode方法,所以他们的hahcode会相同吗?当然是不同的,因为我new两个user对象【u1、u2】他们都的内存地址是不一样的,所以hashcode由内存地址转换为整数也必然不相同。
public class main {
public static void main(String[] args){
User u1 = new User("zhangsan", 123);
User u2 = new User("zhangsan", 123);
System.out.println(u1.hashCode());
System.out.println(u2.hashCode());
}
}
当我们往Set集合中存放时,u1和u2都能放进去因为虽然equals判断他俩相等,但是hashcode没有重写所以根据上述判断是否是重复元素的规则【1.hashcode是否相等2.调用equals方法是否相等】的第一层就没通过,则u1和u2都可以放进去set集合中,不判定为重复元素。
public class main {
public static void main(String[] args){
User u1 = new User("zhangsan", 123);
User u2 = new User("zhangsan", 123);
Set<User> s=new HashSet<>();
s.add(u1);
s.add(u2);
System.out.println(s.size());
}
}
所以重写了equals需要重写hashcode方法,不然会破坏set的去重性。
当我们重写了hashcode方法时
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (this==obj) return true;
if (obj==null||this.getClass()!=obj.getClass()) return false;
User u1 = (User) obj;
return this.age== u1.age&& Objects.equals(this.name,u1.name);
}
@Override
public int hashCode() {
return Objects.hash(name,age);
}
}
此时u1和u2的hashcode相等了
public class main {
public static void main(String[] args){
User u1 = new User("zhangsan", 123);
User u2 = new User("zhangsan", 123);
System.out.println(u1.hashCode());
System.out.println(u2.hashCode());
}
}
因此重写了equals和hashcode方法以后,上述u1和u2会变为相同对象,也不会影响set的去重性
public class main {
public static void main(String[] args){
User u1 = new User("zhangsan", 123);
User u2 = new User("zhangsan", 123);
Set<User> s=new HashSet<>();
s.add(u1);
s.add(u2);
System.out.println(s.size());
}
}