声明在哪?
equals() 和 hashCode() 声明在所有类的父类Object类中
public class Object {
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
}
解释:
- equals 方法
- 当x和y引用的是同一个对象时,此方法返回true
- hashCode 方法
- navite 代表这是一个本地方法,作用:用来返回对象的哈希值(一个整数)。在Java程序执行期间,对一个对象调用此方法必须返回同样的哈希值
在源码中,这两个方法上有注释,大概是这个意思:
1. 如果两个对象调用 equals() 返回true,那么调用hashCode() 也必须得到相同的整数结果
2. 每当重写 equals() 时,hashCode() 也应该重写。和上一条要求相对应
hashCode() 的作用:是用来获取哈希值,而盖哈希值的作用是能根据此哈希值得到此对象在哈希表中的索引位置。
哈希表的典型代表是 HashMap
我们使用 HashSet 来演示,HashSet 的底层也是拿 HashMap 实现的
public HashSet() {
map = new HashMap<>();
}
为什么重写了 equals() 还要重写 hashCode()
来看下面这段代码:
public class EmpDTO {
//主键
private Long id;
//原密码
private String rawPassword;
//新密码
private String password;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EmpDTO empDTO = (EmpDTO) o;
if (id != null ? !id.equals(empDTO.id) : empDTO.id != null) return false;
if (rawPassword != null ? !rawPassword.equals(empDTO.rawPassword) : empDTO.rawPassword != null) return false;
return password != null ? password.equals(empDTO.password) : empDTO.password == null;
}
public static void main(String[] args) {
Set<EmpDTO> set = new HashSet<>();
EmpDTO e1 = new EmpDTO();
e1.setId(1L);
EmpDTO e2 = new EmpDTO();
e2.setId(1L);
set.add(e1);
System.out.println("e1.equals(e2) = " + e1.equals(e2));
System.out.println("e1.hashCode() = " + e1.hashCode());
System.out.println("e2.hashCode() = " + e2.hashCode());
for (EmpDTO empDTO : set) {
System.out.println(empDTO);
}
}
}
在阅读下面的逻辑前,我们应该先了解一下 HashSet 的一点原理:
Set 的特点:无序性,不可重复性
好了,我们已经简单了解了 HashSet 的原理了,现在让我们往下走
我们new了一个 set 集合,往里面放了两个 `EmpDTO`类的对象。而我们重写了 `EmpDTO` 的类的 equals 方法,我们new了两个 `EmpDTO` 的两个对象,此时使用 equals 方法进行比较,结果为 `true`。此时遍历 set 集合中,有两个 `EmpDTO` 类的对象:
输出结果:
原因:因为两个对象的 hash 值不相同,所以在 HastSet 中存储的位置也不同,所以能添加成功
现在我们来重写 hashCode() 方法,
hashCode():
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (rawPassword != null ? rawPassword.hashCode() : 0);
result = 31 * result + (password != null ? password.hashCode() : 0);
return result;
}
此时再执行,main方法中代码逻辑后,得出的结果为:
此时 set 中也只有一个元素了,问题解决!
每当重写 equals 方法时,hashCode 方法也需要重写。是为了保证:如果两个对象调用 equals() 方法返回的结果为 true ,那么两个对象调用 hashCode() 方法返回的哈希值也必然相同!
好了,晚安。