Java equals 和 hashCode 的这几个问题可以说明白吗?

上一篇文章 如何妙用 Spring 数据绑定? ,灵魂追问 环节留下了一个有关 equals hashcode 问题 。基础面试经常会碰到与之相关的问题,这不是一个复杂的问题,但很多朋友都苦于说明他们二者的关系约束,于是写本文做单独说明,本篇文章将循序渐进 ( 通过举例,让记忆与理解更轻松 ) 说明这些让你有些苦恼的问题,Let's go .......

面试问题 1. Java 里面有了 == 运算符,为什么还需要 equals

== 比较的是对象地址,equals 比较的是对象值

先来看一看 Object 类中 equals 方法:

public boolean equals(Object obj) { return (this == obj); }

我们看到 equals 方法同样是通过 == 比较对象地址,并没有帮我们比较值。Java 世界中 Object 绝对是"老祖宗" 的存在,== 号我们没办法改变或重写。但 equals 是方法,这就给了我们重写 equals 方法的可能,让我们实现其对值的比较:

@Override public boolean equals(Object obj) { //重写逻辑 }

新买的电脑,每个电脑都有唯一的序列号,通常情况下,两个一模一样的电脑放在面前,你会说由于序列号不一样,这两个电脑不一样吗?

如果我们要说两个电脑一样,通常是比较其「品牌/尺寸/配置 」(值) ,比如这样:

@Override public boolean equals(Object obj) { return 品牌相等 && 尺寸相等 && 配置相等 }

当遇到如上场景时,我们就需要重写 equals 方法。这就解释了 Java 世界为什么有了 == 还有equals 这个问题了.

2. equals相等 和 hashcode 相等问题

关于二者,你经常会碰到下面的两个问题:

两个对象 equals 相等,那他们 hashCode 相等吗?

两个对象 hashCode 相等,那他们 equals 相等吗?

为了说明上面两个问题的结论,这里举一个不太恰当的例子,只为方便记忆,我们将 equals 比作一个单词的拼写;hashCode 比作一个单词的发音,在相同语境下:

sea / sea 「大海」,两个单词拼写一样,所以 equals 相等,他们读音 /siː/ 也一样,所以 hashCode 就相等,这就回答了第一个问题:

两个对象 equals 相等,那他们 hashCode 一定也相等

sea / see 「大海/看」,两个单词的读音 /siː/ 一样,显然单词是不一样的,这就回答了第二个问题:

两个对象 hashCode 相等,那他们 equals 不一定相等

查看 Object 类的 hashCode 方法:

public native int hashCode();

继续查看该方法的注释,明确写明关于该方法的约束

Java equals 和 hashCode 的这几个问题可以说明白吗?

其实在这个结果的背后,还有的是关于重写 equals 方法的约束

3. 重写 equals 有哪些约束?

关于重写 equals 方法的约束,同样在该方法的注释中写的很清楚了,我在这里再说明一下:

Java equals 和 hashCode 的这几个问题可以说明白吗?

赤橙红绿青蓝紫,七彩以色列;哆来咪发唆拉西, 一曲安哥拉 ,这些规则不是用来背诵的,只是在你需要重写 equals 方法时,打开 JDK 查看该方法,按照准则重写就好

4. 什么时候需要我们重写 hashCode?

为了比较值,我们重写 equals 方法,那什么时候又需要重写 hashCode 方法呢?

通常只要我们重写 equals 方法就要重写 hashCode 方法

为什么会有这样的约束呢?按照上面讲的原则,两个对象 equals 相等,那他们的 hashCode 一定也相等。如果我们只重写 equals 方法而不重写 hashCode 方法,看看会发生什么,举个例子来看:

定义学生类,并通过 IDE 只帮我们生成 equals 方法:

public class Student { private String name; private int age; @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); } }

编写测试代码:

Student student1 = new Student(); student1.setName("日拱一兵"); student1.setAge(18); Student student2 = new Student(); student2.setName("日拱一兵"); student2.setAge(18); System.out.println("student1.equals(student2)的结果是:" + student1.equals(student2)); Set<Student> students = new HashSet<Student>(); students.add(student1); students.add(student2); System.out.println("Student Set 集合长度是:" + students.size()); Map<Student, java.lang.String> map = new HashMap<Student, java.lang.String>(); map.put(student1, "student1"); map.put(student2, "student2"); System.out.println("Student Map 集合长度是:" + map.keySet().size());

查看运行结果:

student1.equals(student2)的结果是:true Student Set 集合长度是:2 Student Map 集合长度是:2

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzpwpd.html