背景
假设我们可能会遇到两个对象,它们的属性都是一样。
而我们的需求 要认为这两对象是同一个,但是在JAVA上它们两是不同的对象,使用equals时就会返回false。
所以我们要重写equals。
public class MyUser {
public String id;
public MyUser(String id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof MyUser){
return id.equals(((MyUser)obj).id);
}
return false;
}
public static void main(String[] args) {
MyUser a = new MyUser("1");
MyUser b = new MyUser("1");
System.out.println(a.equals(b));
//输出:true
}
}
这时候两个同ID不同对象使用equals就相等了。
但是!我们使用Set集合的时候就出现了问题。
HashSet<MyUser> mySet = new HashSet<>();
mySet.add(a);
mySet.add(b);
System.out.println(mySet);
//输出:[com.malu.bili.acquisition.util.MyUser@4ccabbaa, com.malu.bili.acquisition.util.MyUser@108c4c35]
我们用Set集合保存了上面的a和b。
我们的需求要认为这个两个是一个对象,那保存到Set肯定会进行去重。
然而,HashSet里面依然保存两个对象。
原因是HashSet是基于HashMap实现,而HashMap需要使用hashcode计算对象保存的位置。
而没有重写hashcode,他们的hashcode是不一样的(极大概率),所以计算出来的位置是不一样的,不能保存到同一个位置。
所以!我们要重写hashcode
public class MyUser {
public String id;
public MyUser(String id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof MyUser){
return id.equals(((MyUser)obj).id);
}
return false;
}
@Override
public int hashCode() {
return id.hashCode();
}
}
这样解决了,Set里面就只保存了一个对象。
这边我偷了个懒,因为只有id一个属性,我就直接返回了id的hashcode。
假设我的对象不止有id,它还有name和age,那该怎么重写?
如何重写hashcode方法
@Override
public int hashCode() {
int hash = 17;
hash = hash * 31 + getId().hashCode();
hash = hash * 31 + getName().hashCode();
hash = hash * 31 + getAge();
return hash;
}
假设如果不想自己写,而你项目恰好还用了Lombok。
在类上使用 @EqualsAndHashCode
@EqualsAndHashCode
public class MyUser {
public String id;
public String name;
public int age;
}
总结
所以你们有遇到需要重写hashcode的情况嘛?
我是没遇到。