为什么重写了equals方法后,也要重写hashCode方法?
equals方法:一、根据Java1.8官方文档中对与equals方法的形貌:
equals方法属于Object类(根类)。指示其他对象是否“等于”这个对象。
等式方法实现了非空对象引用的等价关系:
1. 它是自反的:对于任何非空引用值x,x.equals(x)应该返回true。
2. 它是对称的:对于任何非空引用值x和y,x.equals(y)应该返回true,当且仅当y.equals(x)返回true。
3. 它是传递的:对于任何非空引用值x、y和z,如果x.equals(y)返回true,y.equals(z)返回true,则x.equals(z)应返回true。
4. 它是一致的:对于任何非空引用值x和y,x.equals(y)的多次调用一致返回true或始终返回false,前提是不修改用于对象等比较的信息。
5. 对于任何非空引用值x:x.equals(null)应返回false。
类Object的相称方法实现了对象上最具辨别性的等价关系;也就是说,对于任何非空引用值x和y,此方法返回true,当且仅当x和y引用同一对象(x == y的值为true)。
请留意,每当此方法被重写时,通常都需要覆盖hashCode方法,以维护hashCode方法的一样平常合同,该合同规定相称对象必须具有相称的哈希代码。
二、根据源码:
https://i-blog.csdnimg.cn/blog_migrate/439ffa6b23235b242aef90819464127c.png
*通过以上两点我们可以发现equals方法的本质是用于比较两个对象的内存所在是否雷同。
让我们通过一个例子明白equals方法:
https://i-blog.csdnimg.cn/blog_migrate/a5ce06a52d9da7110cb739ea5ad35d0f.png
当o1/o2均为 new 出来的对象时,它们在 堆内存 中拥有两块 差别的空间,此时o1和o2两个引用(存在于栈内存)分别指向两个差别的堆内存所在。这时调用equals方法返回的结果为 false :
https://i-blog.csdnimg.cn/blog_migrate/17dc54ea53eda55ca28c665f2f095b23.png
当o2为o1对象的引用复制时,o2引用同样指向o1对象,此时o1/o2两个引用 对应雷同的所在,而0x1001(原o2对象)对象由于不再有引用指向它,将被 垃圾接纳器 销毁,此时调用equals方法的返回值为 true:
https://i-blog.csdnimg.cn/blog_migrate/5a6da41227764e3fd2175b1f30834487.png
https://i-blog.csdnimg.cn/blog_migrate/ff5844ea3844997831178aa51164471b.png
三、我们可以通过String类对equals方法的重写加深明白:
https://i-blog.csdnimg.cn/blog_migrate/d165fca5bdb99db180804ca292b094b7.png
在String类对equals方法的重写源码中我们可以看到:起首对于 所在 进行判断,如果两个对象的所在雷同,则返回 true,否则判断两个字符串的 值是否雷同 ,如果值雷同则返回 true,反之亦然。
hashCode方法:
我们需要知道,在 Java 中的任何一个对象都包含一个 native 的 hashCode 方法:
https://i-blog.csdnimg.cn/blog_migrate/aa198b5c986628023610117eaa34ad36.png
*这是Object类对于hashCode方法的定义
在散列存储结构中,我们在新增元素时需要判断新增的元素是否已经存在于集合中,如果利用equals方法,效率过于低下,以是利用hashCode办理这个问题:如果集合中不存在与新增元素雷同的hashCode值,则将新元素直接参加存储结构中;如果集合中存在与新增元素雷同的hashCode值则调用equals方法进行进一步的比较,如果雷同则覆盖,如果不雷同则散列到其他所在,这使得调用equals方法的概率大大低落提高了存储速度。
hashCode就是 对象的哈希码,默认环境下hashCode返回的是对象的存储所在映射成一个数值,也可以重写hashCode方法来实现本身的哈希码逻辑,通过哈希码可以提高查询的效率,重要用于在哈希表(散列表)结构中快速确定对象的存储所在,如HashMap、HashSet中。
需要留意的是:
1. 由于hashCode是JVM利用随机数生成,以是两个差别的对象可能会产生雷同的hashCode值,可能造成哈希冲突问题。
2. 如果两个对象完全雷同,即它们的内存所在雷同,则它们的hashCode值一定雷同。
结合分析:
我们先建立一个只重写equals方法的Student类:
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
/*Attention!*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
}
对于equals方法,我们先对内存所在进行判断,如果内存所在差别,再根据年龄和姓名的值进行判断。
在Main类中测试:
public class Main {
public static void main(String[] args) {
Student std1 = new Student("test", 18);
Student std2 = new Student("test", 18);
System.out.println("std1 & std2 are the same: " + std1.equals(std2));
Set<Student> students = new HashSet<>();
students.add(std1);
students.add(std2);
for (Student student : students) {
System.out.println("name: " + student.getName() + ", age: " + student.getAge());
}
}
}
创建std1和std2对象,利用构造方法赋初值(name = test,age = 18)。我们起首调用equals方法,判断两个对象是否雷同,由于在Student类中重写了equals方法 ,故equals的返回值应为 true。我们继续将两个Student对象(std1、std2)参加到Set集合中(set集合为散列存储结构,而且不允许出现重复元素)。末了我们迭代这个Set集合(students),不停输出集合中的内容,由于两个对象先前调用过equals方法,说明这两个对象在 逻辑上 应该为 雷同 的对象,不应该在集合中重复出现。
我们运行步伐检察结果:
std1 & std2 are the same: true
name: test, age: 18
name: test, age: 18 两个雷同的对象居然同时出如今了Set集合中!继续分析,我们利用new关键字创建了两个Student对象,根据先前的介绍,这两个对象在堆内存中位于差别的所在,而hashCode值又与所在有关,以是这两个对象的hashCode值差别,而在散列存储结构中添加元素时,起首判断新元素的hashCode值是否在集合中存在,当前环境下显然是不存在,Set集合将雷同的“新”元素添加进了存储结构中。
故继续重写hashCode方法:(在Studen类中添加以下代码)
@Override
public int hashCode() {
return Objects.hash(name, age);
} 此处的hashCode方法利用Objects中提供的hash方法,其本质如下:
https://i-blog.csdnimg.cn/blog_migrate/76d9eec490facb4e687a78ef07c08aec.png
再次在Main类中测试:
std1 & std2 are the same: true
name: test, age: 18 结果与逻辑符合合,问题乐成办理了。
总结:
如果只重写equals方法,不重写hashCode方法,就有可能导致在 x.equals(y) 表达式成立的条件下,x 和 y 的 hashCode 值却不雷同。此时这个只重写了 equals 方法的对象在利用散列集合进行存储的时候,由于散列集合利用 hashCode 来确定 key 的位置,如果存储两个完全雷同的对象但是这两个对象有差别的hashCode值,就会出现两个雷同的对象储存在散列集合的差别位置,违反了散列集合的规则,也会造成该类对象无法利用散列存储结构。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]