背景
假设我们可能会遇到两个对象,它们的属性都是一样。
而我们的需求 要认为这两对象是同一个,但是在JAVA上它们两是不同的对象,使用equals时就会返回false。
所以我们要重写equals。
public class MyUser {public String id;public MyUser(String id) {this.id = id;}@Overridepublic 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;}@Overridepublic boolean equals(Object obj) {if(obj instanceof MyUser){return id.equals(((MyUser)obj).id);}return false;}@Overridepublic 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的情况嘛?
我是没遇到。