Java 中 equals() 和 hashcode() 方法详解
时间:2021-08-23
本文章向大家介绍Java 中 equals() 和 hashcode() 方法详解,主要包括Java 中 equals() 和 hashcode() 方法详解使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
hashCode 使用中产生的问题
HashSet 是一个无序、不可重复的集合,代码如下:
public class HashSetDemo {
public static void main(String[] args) {
Set<Student> sets = new HashSet<>();
sets.add(new Student(1,"张三",23));
sets.add(new Student(2,"李四",24));
sets.add(new Student(3,"王五",22));
sets.add(new Student(4,"赵六",27));
sets.add(new Student(4,"赵六",27));
for (Student student: sets) {
System.out.println(student);
}
}
}
运行打印结果如下:
Student{id=4, name='赵六', age=27, clazz='null', score=0.0}
Student{id=3, name='王五', age=22, clazz='null', score=0.0}
Student{id=4, name='赵六', age=27, clazz='null', score=0.0}
Student{id=1, name='张三', age=23, clazz='null', score=0.0}
Student{id=2, name='李四', age=24, clazz='null', score=0.0}
是不是结果和我们想象的不一样,HashSet 集合元素不是不重复,为何这里却发生的重复现象呀?这其实是因为 equals、hashCode 使用不规范导致的。那么,equals 和 hashCode 到底有何关系呢?为何影响 HashSet 的使用?
equals 与 Hashcode 的关系
它们都是 Object 类中的方法,如下:
public boolean equals(Object obj)
public int hashCode()
- equals(): 用来判断两个对象是否相同,在 Object 类中是通过判断对象间的内存地址来决定是否相同
- hashCode(): 获取哈希码,也称为散列码,返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。
阅读 hashCode 方法的注释如下:
- hashCode() 方法返回对象的哈希码,支持该方法是为哈希表提供一些优点,例如,HashMap 提供的哈希表。
- 同一个对象未发生改变时多次调用 hashCode() 返回值必须相同
- 两个对象 equals 不相等,那么两对象的 hashCode() 返回必定不同(此处可用来提高哈希表性能)
- 两个对象的 hashCode() 返回值相同,两对象不一定相同,还需要通过 equals() 再次判断
- 当 equals 方法被重写时,通常有必要重写 hashCode 方法
通过第 1 点其实可以看出,hashCode() 在散列表中才有用,在其它情况下没用。在散列表中 hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置,当对象不会用来创建像 hashMap、hashSet 等散列表时,hashCode() 实际上用不上。
产生问题的原因
分析原因前需要了解哈希表的底层实现,hashCode 在哈希表中充当的作用:
- 假设内存中有0 1 2 3 4 5 6 7 8这8个位置,如果我有个字段叫做 ID,那么我要把这个字段存放在以上8个位置之一,如果不用HashCode而任意存放,那么当查找时就需要到8个位置中去挨个查找
- 使用 HashCode 则效率会快很多,把ID的 HashCode%8,然后把 ID 存放在取得余数的那个位置,然后每次查找该类的时候都可以通过ID的 HashCode%8 求余数直接找到存放的位置了
- 如果 ID 的HashCode%8 算出来的位置上本身已经有数据了怎么办?这就取决于算法的实现了,比如 ThreadLocal 中的做法就是从算出来的位置向后查找第一个为空的位置,放置数据;HashMap 的做法就是通过链式结构连起来。反正,只要保证放的时候和取的时候的算法一致就行了。
- 如果ID的 HashCode%8 相等怎么办(这种对应的是第三点说的链式结构的场景)?这时候就需要定义 equals 了。先通过HashCode%8 来判断类在哪一个位置,再通过 equals 来在这个位置上寻找需要的类。对比两个类的时候也差不多,先通过HashCode 比较,假如 HashCode 相等再判断 equals。如果两个类的 HashCode 都不相同,那么这两个类必定是不同的。
其实在 HashSet 就是采用的这种存储和获取方式,通过 HashCode 和 equals 组合的方式来保证集合无重复。也说明了 HashCode() 在散列表中是发挥作用的
hashCode 的正确使用
从 JDK 源码的注释中可以看出,hashCode() 在散列表中才会发挥作用,当对象无需创建像 HashMap、HashSet 等集合时,可以不用重写 hashCode() 方法,但是如果有使用到对象的哈希集合等操作时,必须重写 hashCode() 和 equals()。
原文地址:https://www.cnblogs.com/binbingg/p/14450595.html
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- OkHttp请求耗时统计
- Ubuntu 18.04 通过 Docker 快速部署 Smokeping 2.6.11 教程
- MySQL 8.0新特性 — 函数索引
- Docker快速上手指北(一)【技术创作101训练营】
- leetcode树之二叉搜索树的最近公共祖先
- 【技术创作101训练营】技术角 | 在CentOS 8上使用Nginx 1.18: 基本配置
- Java诊断应用之Arthas实战(技术创作101训练营)
- 突击并发编程JUC系列-数组类型AtomicLongArray
- 个人量化投资体系搭建(一)
- 服务端的 WebAssembly 与 Rust 入门篇
- pImpl
- Flask+requests发起页面请求示例
- 【技术创作101训练营】Git 如何成功配置SSH key连接多个代码平台?
- 深入浅出iOS内存管理-技术创作101训练营
- 聊聊原型 Prototype | 技术创作101训练营