覆盖equals方法时需要注意什么以及为什么同时也要覆盖hashcode方法?
覆盖equals方法时需要注意什么以及为什么同时也要覆盖hashcode方法?
首先,贴上一个重写equals方法和hashcode方法的对象的实例代码:
public class Demo1 {
private Integer id;
private String name;
private String orgNames;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getOrgNames() {
return orgNames;
}
public void setOrgNames(String orgNames) {
this.orgNames = orgNames;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Demo1 demo1 = (Demo1) o;
return
Objects.equals(id, demo1.id) &&
Objects.equals(name, demo1.name) &&
Objects.equals(orgNames, demo1.orgNames);
}
@Override
public int hashCode() {
return Objects.hash(id, name, orgNames);
}
}
众所周知,Java的Object类是实现了equals方法的,实现规则是:类的每个对象都只与它自身相等。
看一下下面的例子,输出结果是什么(该类没有覆写equals方法):
public void get(){
DemoEH demoEH = new DemoEH();
demoEH.setName("name");
demoEH.setId("id");
DemoEH demoEH1 = new DemoEH();
demoEH1.setName("name");
demoEH1.setId("id");
boolean equals = demoEH.equals(demoEH1);
System.out.println(equals);
}
---------------------------------result----------------------------------------
false
很明显,控制台输出结果为false。
在说明什么情况下需要重写equals方法之前,我们先说明一下,什么情况不需要重写:
- 类的每个实例本质上都是唯一的。
- 类没有必要提供逻辑相等的测试功能。
- 超类已经覆盖了equals,超类的行为对于这个类也是合适的。
- 类是私有的,或者是包级私有的,可以确定他的equals方法永远不会被调用。
就像上边我们写的这个例子,两个对象的值是一样的(我们理解为逻辑相等),但是调用Object的equals方法我们发现,返回的是false,这种情况下我们如果想让其返回true的话,就需要重写equals方法。
那么我们在什么时候应该覆盖equals方法呢?
如果类具有自己特有的“逻辑相等”概念(不同于对象等同的概念),而且超类还没有覆盖equals。
在覆盖equals方法时,必须要遵守他的通用约定,即:
- 自反性
- 对称性
- 传递性
- 一致性
- 非空性
切记,一旦违反了equals约定,当其他对象面对你的对象时,你完全不知道这些对象的行为会怎么样。
那么在覆盖equals时,为什么总要覆盖hashcode方法呢?
首先我们需要了解一下hashcode的通用规范(这是你必须要知道的):
- 在应用的执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么对同一个对象的多次调用,hashcode方法都必须始终返回同一个值。在一个应用程序与另一个应用程序的执行过程中,执行hashcode方法所返回的的值可以不一致。
- 如果两个对象根据equals方法比较是不相等的,那么调用这两个对象的hashcode方法必须产生同样的整数结果。
- 如果两个对象根据equals方法比较是不相等的,那么调用这两个对象中的hashcode方法,则不一定要求hashcode方法必须产生不同的结果。
如果我们在覆盖了equals方法时没有覆盖hashcode的话,就违反了相等的对象必须具有相等的散列码(hashcode)这一约定。
那么散列码在我们的程序中有什么作用呢?
举个例子,HashMap中有一项优化,可以将与每个项相关联的散列码缓存起来,如果散列码不匹配,也就不再去检验对象的等同性。这句话是什么意思呢,就是我们定义了一个map,我们在获取其中某一个key的值时,hashmap会先去寻找这个key的对象的hashcode,如果没有找到相同的hashcode值,那么就不会再去找这个对象的key了,就会直接返回空。
ps:不理解的话可以先了解一下hashMap
所以对于我们的程序来讲,重写equals之后重写hashcode是必要的。