今天在用阿里代码检查工具检查项目的时候,发现了一个警告
Map/Set的key为自定义对象时,必须重写hashCode和equals
说明为:
1) 只要重写equals,就必须重写hashCode。
2) 因为Set存储的是不重复的对象,依据hashCode和equals进行判断,所以Set存储的对象必须重写这两个方法。
3) 如果自定义对象做为Map的键,那么必须重写hashCode和equals。
下面是代码的写法(伪代码)
public void methodDemo(){
Set hashSet = new HashSet();
hashSet.add(new ObjDemo("1","对象1"));
hashSet.add(new ObjDemo("2","对象2"));
}
ObjDemo类很简单
class ObjDemo{
private String id;
private String name;
public ObjDemo(String id,String name){
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
为什么会报这个警告?
警告中也说明了,因为Set存储的是不重复的对象,依据hashCode和equals进行判断,所以Set存储的对象必须重写这两个方法。
equals和hashCode的关系(这个是规定):
1、如果两个对象相同(即用equals比较返回true),那么它们的hashCode值一定要相同;
2、如果两个对象的hashCode相同,它们并不一定相同(即用equals比较返回false)
hashCode()方法是干什么的,这里提示了是重写,那么原来其实是有一个hashCode的,在Object类中,这里的hashCode()存放的是对象的内存地址
所以我们在存放对象进入hashSet的时候,如果不重写equals()和hashCode(),像下面这段代码
public void methodDemo(){
Set hashSet = new HashSet();
hashSet.add(new ObjDemo("1","对象1"));
hashSet.add(new ObjDemo("1","对象1"));
}
其实我们逻辑上放进去的是一个对象,因为id、name都相等,但是,如果打断点或者写个测试方法去输出hashSet长度的时候,会发现在hashSet中却有两个对象,因为这两个对象的内存地址是不同的。所以要重写equals()和hashCode()方法。例如根据id来比较两个对象是否相等,以及根据id取hashCode,在ObjDemo中加入
@Override
public boolean equals(Object o) {
if (o instanceof ObjDemo){
ObjDemo obj = (ObjDemo)o;
return id.equals(obj.id);
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
这样往hashSet中放对象时就会根据id去判断,不会重复添加。
面试题:为什么重写equals()方法要重写hashCode()方法
从上面的规定可以知道,如果只重写了equals()方法不重写hashCode()方法,那么则违反了如果两个对象相同(即用equals比较返回true),那么它们的hashCode值一定要相同
也可以把上面的代码中的hashCode()方法去掉,添加2个id为1的对象,set集合里的数据还是为2条。
所以得出结论:如果一个类重写了equals方法但是没有重写hashCode方法,那么该类无法结合所有基于散列的集合(HashMap,HashSet)一起正常运作。