首页 > 其他分享 >一文搞懂 == 、equals和hashCode

一文搞懂 == 、equals和hashCode

时间:2022-11-12 11:33:23浏览次数:42  
标签:相等 对象 方法 equals hashCode 搞懂 重写

面试的时候,经常会被问到==和equals()的区别是什么?以及我们也知道重写equals()时候必须重新hashCode()。这是为什么?既然有了hashCode()方法了,JDK又为什么要提供equals()方法呢?如果在重写equals()时候没有重写hashCode(),在使用HashMap或HashSet的时候可能会出现什么情况?​

一文搞懂​

== 和 equals()的区别是什么?​

先来看看​

Java中使用==的时候,如果左右两边是基本类型和两边是应用类型的作用效果是不同的:​

我们看看下面如下代码:​

int x = 128;
int y = 128;
Person p = new Person(new Address("北京"));
Person p2 = p.clone();
System.out.println("两个基本类型==后值:");
System.out.println(x==y);
System.out.println("两个对象(引用类型)==后值:");
System.out.println(p == p2);
System.out.println(" \n p的地址值为:"+p +" \n p2的地址值为:"+p2.toString());​

输出的结果是什么?​

一文搞懂 == 、equals和hashCode_内存地址


从上面结果,我们可以得到如下结论:​

当​

当​

需要注意:​

因为 Java 只有值传递,所以,对于 == 来说,不管是比较基本数据类型,还是引用数据类型的变量,其本质比较的都是值,只是引用类型变量存的值是对象的地址。

再看看equals()​

equals()方法特点:​

1:equals()方法不能用于判断基本类型的变量,只能用来判断两个对象是否相等。​

2:equals()方法存在于Object类中的。而我们又指导Object类是所有类的直接或者间接的父类。所以所有类都具有equals()方法​

看看Object源码中equals()方法:​

一文搞懂 == 、equals和hashCode_基本类型_02


从源码中我们可以看出,底层其实使用的是​

== 左右两边都是对象。从上面我们知道==比较对象,其实就是比较对象内存中的地址值。​

所以,我们可以得到equals()方法存在两种使用情况的结论:​

1:类没有重写equals()方法:​

当两个对象没有重写equals()方法时候,通过equals()方法进行比较的时候,其实就等价于通过"=="比较两个对象。因为在没有重新equals方法的情况下默认都使用的是Object类的equals()方法;​

2:类重写了equals()方法:​

一般在工作中,我们都重写equals()方法来比较两个对象中的属性是否相等。如果两个对象的属性相等,则返回true.就认为两个对象是相等的。​


代码如下:​

定义一个Girl对象,有两个属性:样貌和肤色。然后重写equals()方法​

一文搞懂 == 、equals和hashCode_java_03


测试重写了equals()方法后,两个girl通过equals比较:​

一文搞懂 == 、equals和hashCode_内存地址_04


我们来看看输出的结果:​

一文搞懂 == 、equals和hashCode_内存地址_05


equal()方法输入的是:true​

但是实际上,两个Girl对象在堆中的内存地址值不一样。​

我们在Girl对象中添加地址对象属性,在重写equals方法:​

一文搞懂 == 、equals和hashCode_java_06


测试:​

一文搞懂 == 、equals和hashCode_java_07

结果:​

一文搞懂 == 、equals和hashCode_java_08


从测试效果来看,可以验证结论:equals()比较两个重新equals()方法对象的时候,其实就是比较的是两个对象中每个属性值。​

现在再来回答​

接下来,我们在来看看hashCode()方法​

hashcCode是什么?​

我们在调用对象的hashCode()方法的时候,返回的是一个int整数。这个整数其实是散列码,不过我们习惯称之为哈希码。作用就是确定这个对象在hash表中的所以位置。​

出处:​

hashCode()方法被定义在Object类中。这也就意味着任何一个类都有hashCode()这个方法(和equals()方法一样,都是被定义在Object对象中)。查看Object的源码,我们可以发现,次方法被native关键字修饰的。也就是说,Object中的hashCode()方法调用的是本地方法的。其实就是调用操作系统自己的hashCode()方法(用C语言或者是C++语言实现的)。该方法通常用来将对象的内存地址转换成整数后返回的。​

一文搞懂 == 、equals和hashCode_内存地址_09


那么为什么要有hashCode?​

起始hash存储的是键值对(K-V)形式的,其特点就是:能够根据"key"快速的检索出对应的"值"。在快速检索的时候,就使用到了哈希码。​

回想下hashMap在put对象的时候,先计算出key对应的hashCode值,来判断对象需要加入的位置。如果不存在,就直接插入,如果存在,就加到链表中。如下图:​

一文搞懂 == 、equals和hashCode_java_10


从上面我们可以知道,起始​

问题:既然两个方法都是比较对象是否相等,那么为什么JDK还要同时提供这两个方法呢?

答:为了提高效率。​

还以hashMap的put方法为例,我们知道,先计算出hashCode,如果不存在,就可以直接put了。不用比较了,少了一次比较。效率就高了。​

问题:那么能否只使用hashCode()方法呢?

答:不能。因为我们知道,哈希码是通过函数算出来的整数。既然使用的是公式,那么可能出现两个对象不一样,但是哈希码一样的。​

就比如我们使用​

经过公式计算的结果都是8,但是两个算式的a和b却是不相等的。​

问题:如果两个对象的hashCode值相等,它们相等吗?

答:不相等。如:4+4 = 8;5+3=8;​

通过上面说明,我们可以得到hashcode相关结论:​

1:两个对象hashcode想的,那么这两个对象不一样相等(hash碰撞了。如:4+4 = 8;5+3=8;)​

2:如果两个对象的hashCode值不相等,那么这两个对象就不相等​

通过上面我们分析equals()方法,我们还可以得到下面这个结论:​

3:如果两个对象的hashCode想的呢并且equals()方法返回的也是true。那么我们才能认为这两个对象相等的。​

因为:4+4 = 8;4+4 = 8; 其中的8就是hashCode. 两个算式的 a、b都是4,也是相等的。​

问题:为什么重写equals()时候必须重写hashCode()方法?

因为一般在重写equals()方法的时候,是要对两个对象进行比较的。如果两个对象相等的话,hashCode值必须相等,equals()方法判断两个对象也是相等的。​

如果重写equals()方法时候,没有重写hashCode()方法的话,可能导致equals()方法判断想的的两个对象hashCCode值却不相等。如下示例:​

一文搞懂 == 、equals和hashCode_内存地址_11


我们来看看结果:​

一文搞懂 == 、equals和hashCode_基本类型_12


总结:​

重写equals()方法是好,必须要重写hashCode()方法。​


思考:重写equals()方法时候,没有重写hashCode()方法的haul,在使用HashMap/HashSet时候可能会出现什么问题?

我们以hashSet为例(hashSet底层使用的是hashMap来实现的):​

一文搞懂 == 、equals和hashCode_基本类型_13


结果:​

一文搞懂 == 、equals和hashCode_基本类型_14


(꒪ꇴ꒪(꒪ꇴ꒪ ;)哈? 不是说hashSet是唯一的,不能有重复的吗?打印出来的set集合大小是2啊,不是1啊。​

其实,这就是只重写了equals(),没有重写hashCode()方法的后果。​

因为在set.add()方法时候,先判断hashcode值,从上图我们可以看到,两个对象hashCode值不相等。set就认为不是一个对象,所以大小就是2了。​

so,我们在重写equals()方法的时候,一定要重写hashCode()方法​

标签:相等,对象,方法,equals,hashCode,搞懂,重写
From: https://blog.51cto.com/kaigejava/5846579

相关文章

  • 一文搞懂 == 、equals和hashCode
    面试的时候,经常会被问到==和equals()的区别是什么?以及我们也知道重写equals()时候必须重新hashCode()。这是为什么?既然有了hashCode()方法了,JDK又为什么要提供equals()方法......
  • 一文搞懂Path环境变量
    什么是Path环境变量?在探讨这个问题之前,我们需要了解什么是环境变量。“环境变量”和“path环境变量”其实是两个东西,这一点大家一定要区分开,不要混为一谈。“环境变量”......
  • 搞懂伽玛(Gamma)校正
    对于几乎所有数字图像系统,伽玛(Gamma)都是一个很重要,但是很难懂的概念。伽玛描述的是像素数值和像素实际亮度之间的关系。没有伽玛,数字摄影机捕捉的颜色(在标准监视器上)就和人......
  • 一文搞懂Go读写Excel文件(下)
    2.4使用Http协议上传并解析Excel文件funcHttpReadExcel(){f:=func(readio.Reader){file,err:=excelize.OpenReader(read)iferr!=nil{......
  • 一文搞懂 SAE 日志采集架构
    简介: 本文将着重介绍了SAE提供了多种日志采集方案,以及相关的架构,场景使用特点,点击下文,立即查看吧~作者:牛通(奇卫) 日志,对于一个程序的重要程度不言而喻。无......
  • Guava中常用Object方法-equals与null比较、hashCode、自定义toString、自定义compareT
    场景Java核心工具库Guava介绍以及Optional和Preconditions使用进行非空和数据校验:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/127683387在上面引入Gua......
  • java中的equals工具包和hashcode
    packagecom.te.jdkapi;importcom.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;importjava.util.Objects;/*学习equals的方法*/publicclassStudy_Equels......
  • 正确使用 equals 方法
    分享知识传递快乐 Object的equals方法容易抛空指针异常,应使用常量或确定有值的对象来调用equals。 举个例子://不能使用一个值为null的引用类型变量来调用非静态方法,否......
  • 为什么重写equals一定要重写hashCode方法?
    分享知识传递快乐  equals方法和hashCode方法都是Object类中的方法。equals方法在其内部是调用了"==",所以说在不重写equals方法的情况下,equals方法是比较两个对象是否具......
  • Java-equals和“==”的区别
    “==”是比较运算符,可以用于判断基本数据类型是否相等,当用于判断引用类型的时候,比较的对象的内存地址是否相同equals是Object类当中的方法,不可以用于判断基本数据是否相......