关于Object中equals方法和hashCode方法判断的分析
作者:Haozz_1994 发布时间:2023-12-23 19:41:53
首先提出这样一个问题:
如果两个对象不相同,他们的hashCode值一定不相等吗?
我们都知道equals和hashCode是Object中的方法,java中每一个对象都具有这两个方法。
equals(Object obj):判断两个对象是否“相同”,返回true或false;
public boolean equals(Object obj) {
return (this == obj);
}
hashCode():将该对象的内部地址作为一个int值返回
public native int hashCode();
再来看两条关于这两个方法的规范:
如果重写equals(Object obj)方法,有必要重写hashCode()方法,以确保equals(Object obj)方法返回为true的两个对象有相等的hashCode()返回值。也就是说,如果两个对象相同,他们的hashCode值应该相等;
如果equals(Object obj)方法返回false,即两个对象不“相同”,并不要求这两个对象调用hashCode()方法有不相等的返回值。也就是说,如果两个对象不相同,他们的hashCode可能相等。
当然,上述只是规范。针对规范1,如果重写equals(Object obj)返回true,而hashCode()方法返回不相等的值,也是可以编译过的。
这样我们可以作出如下推论:
如果两个对象equals,理论上讲他们的hashCode一定相等(至少Java环境会这样认为);
如果两个对象不equals,他们的hashCode有可能相等;
如果两个对象hashCode相等,他们不一定equals;
如果两个对象hashCode不相等,他们一定不equals。
看着有点绕,其实原理很简单。我们从推论3和推论4可以预测:
Java在判断两个对象是否“相同”时,首先判断他们的hashCode()方法是否返回相等的int值,其次判断equals方法是否返回true。
我们可以写一段简单的代码测试一下:
首先写一个Java类:
public class Person {
//重写equals方法,始终返回false;
@Override
public boolean equals(Object obj) {
System.out.println("判断Person的equals");
return false;
}
//重写hashCode方法,始终返回1;
@Override
public int hashCode() {
System.out.println("判断Person的hashCode");
return 1;
}
}
上述代码中Person类重写了equals方法,打印并始终返回false,重写了hashCode方法,打印并始终返回1。
我们都知道Map中要求键不能重复,也就是不能“相同”,所以可以写如下的测试类:
public class TestPerson {
@Test
public void test(){
Map<Person,Object> map = new HashMap<>();
map.put(new Person(),new Object());//放入第1个Person-Object键值对;
System.out.println("=====================");
map.put(new Person(),new Object());//放入第2个Person-Object键值对;
System.out.println(map.size());
}
}
运行,打印结果如下
判断Person的hashCode
=====================
判断Person的hashCode
判断Person的equals
2
我们来分析一下:
当放入第1个Person-Object键值对时,Java会判断map中有没有和当前添加的new Person()相同的对象,于是去调用了Person的hashCode()方法,得到返回值1,发现此时map中没有相等的hashCode为1的Person对象(因为此时map为空),所以不再判断equals方法,将这个键值对放入map中;(推论4:如果两个对象hashCode不相等,他们一定不equals)
当放入第2个Person-Object键值对时,Java依然采用相同的判断方式,hashCode()方法判断之后得到返回值为1,发现此时map中有相等的hashCode值的Person对象,然后再去判断equals方法,得到返回值false(推论3:如果两个对象的hashCode相等,他们不一定equals),认为这两个对象不相同,于是将第2个键值对也放入map中。执行之后得到map的size为2
所以可以得出结论:
Java在判断两个对象是否“相同”时,首先判断他们的hashCode()方法是否返回相等的int值,如果不相等则直接认为他们不“相同”,如果相等,再判断equals方法是否返回true。
针对上述代码,可以在equals方法和hashCode方法中分别打断点,Debug运行,这样会看得比较清楚一点。
我们回到最初的那个问题:如果两个对象不相同,他们的hashCode值一定不相等吗?
上述代码中的场景就充分说明两个对象不相同时hashCode值却相等的场景,当然,这是不按照规范操作的情况。所以写代码时一定要按照规范要求的去做,避免不必要的BUG
可以试想一下,如果将上述代码中重写equals方法中的始终返回false改为始终返回true,又会是怎样的结果。
来源:https://blog.csdn.net/hz_940611/article/details/80365983


猜你喜欢
- 本文实例为大家分享了Unity实现俄罗斯方块第2部分,供大家参考,具体内容如下代码部分1. 实现物体自由降落(在有关于物体的脚本中编写)1)
- 今天介绍下 Aspose.Words 对 word 中的图片进行删除string tempFile = Application.Startu
- 我们知道,Java和MySQL中的数据类型是不同的,Java中除了基本数据类型,还有对象。有时候使用MySQL存储数据,或者从MySQL中读
- 本文实例为大家分享了C#使用Socket实现局域网聊天的具体代码,供大家参考,具体内容如下先运行一个java写的局域网聊天,效果图如下后使用
- 先看一下效果图Tinker已知问题由于原理与系统限制,Tinker有以下已知问题:Tinker不支持修改AndroidManifest.xm
- 前言我曾经在一篇介绍 Compose Navigation 的文章 中提到了 Navigation 的状态保存实际是由 rememberSa
- 网上很多资料在描述Java内存模型的时候,都会介绍有一个主存,然后每个工作线程有自己的工作内存。数据在主存中会有一份,在工作内存中也有一份。
- 集合、数组都是对多个数据进行存储操作(主要是内存层面存储)的结构,简称Java容器。数组的特点1.数组初始化以后,长度确定不可变2.数组定义
- 只要是开发和手机通讯录有关的应用,总要学会获取联系人信息,每次都google很麻烦,怎么办?写一个工具类,获取到通讯录里所有的信息并分好类,
- 前言做Android的这两年时间,通过研究Android源码,也会Java并发处理多线程有了自己的一些理解。那么问题来了,如何实现一个串行的
- 代码分2块,server端:class Program {
- 今天聊一个小伙伴在星球上的提问:问题不难,解决方案也有很多,因此我决定撸一篇文章和大家仔细说说这个问题。1. 配置文件位置首先小伙伴们要明白
- 在 MyEclipse 的可视化 Swing 中,有 JTable 控件。JTable 用来显示和编辑常规二维单元表。那么,如何将 数据库S
- 本文较为详细的分析了C#中sleep和wait的区别。分享给大家供大家参考。具体分析如下:sleep和wait都是使线程暂时停止执行的方法,
- 前言本文主要介绍如何在 Android App 里集成支付宝和微信支付的功能,文中将实现的步骤一步步介绍的非常详细,对同样遇到这个问题的朋友
- Struts2的核心在于它复杂的 * ,几乎70%的工作都是由 * 完成的。比如我们之前用于将上传的文件对应于action实例中的三个属性的
- 一、 java文件中获得路径Thread.currentThread().getContextClassLoader().getResour
- 一、synchronized 有不足新事物的出现要不是替代老事物,要么就是对老事物的补充JUC 的 locks 就是对 synchroniz
- 本文实例为大家分享了c语言实现可自定义的游戏地图的具体代码,供大家参考,具体内容如下博主相信每个人都有想做游戏的冲动,那么本文将给出一个用c
- 本文实例讲述了C#实现读取匿名对象属性值的方法。分享给大家供大家参考,具体如下:通过new出匿名对象,可以直接调用该匿名对象的属性名,获取属