`

一文搞懂 == 、equals和hashCode

阅读更多

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

一文搞懂 == 、equals和hashCode

== 和 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());

输出的结果是什么?

7541e21e96e80d99b39fc9fb582be914.png

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

当 == 左右两边是基本类型的时候,其实就是比较的是数值是否相等;

当 == 左右两边是对象(引用)类型的时候,其实比较的是p和p2这两个对象所指向的堆中的对象地址,一般我们简称:比较的是内存地址值。

需要注意:

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

来看看equals()

equals()方法特点:

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

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

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

468328c746dd09b45dd88aa092324033.png

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

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

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

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

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

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

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

 

代码如下:

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

f9f2934e8819f4260dfbf4b1295270e5.png

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

6f56db2b69ac257e34bfd11de1a81471.png

我们来看看输出的结果:

fe6808d4206e84e913ab74ee8c5329ca.png

equal()方法输入的是:true

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

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

2a8fde8768dcad5e26336b9503c8fb14.png

测试:

3fc68e667b99a066ebb7bc10e489577f.png结果:

9252c5e8101e2d40bd2b9a9de5437aea.png

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

现在再来回答 == 和 equals()方法有什么区别?这个问题应该好回答了吧。

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

hashcCode是什么?

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

出处:

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

29f9a0563db269f0771405fd9aaf5e9c.png

那么为什么要有hashCode?

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

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

18f669b1062cba88212d684dbc69fc4d.png

从上面我们可以知道,起始 hashCode()和equals()这两个方法都是用于比较两个对象是否相等的。

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

答:为了提高效率。

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

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

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

就比如我们使用 a+b这个公式得出的一个整数一样。4+4 = 8;5+3=8;

经过公式计算的结果都是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值却不相等。如下示例:

f4442fdc6899d026a965c25934f10008.png

我们来看看结果:

62a37b24a842a6f3fd27d598146697b3.png

总结:

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

 

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

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

e6a389439c4e3e6b6c5e278c856baf02.png

结果:

748a5e25f229efc76756d145545977c3.png

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

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

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

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

 

 

 

 

0
0
分享到:
评论

相关推荐

    ==和equals的区别

    Java 中的 == 和 equals 方法的区别 在 Java 中,比较值大小有两种方法:== 和 equals,这两个方法的使用场景和比较规则不同,下面我们将详细探讨它们的区别。 基本数据类型和引用数据类型 在 Java 中,有两种...

    ==运算符和Equals()方法区别

    "运算符和Equals()方法区别" 在C#语言中,`==`运算符和`Equals()`方法都是用来比较两个对象是否相等,但是它们之间存在着很大的区别。 对于值类型来说,`==`运算符和`Equals()`方法的行为是一致的,都会比较两个...

    ==与equals的比较

    "Java中的==和equals方法比较" 在Java中,`==`和`equals`是两种不同的比较方法,前者比较引用地址,而后者比较对象的实际内容。 首先,让我们来看看`==`运算符的用法。`==`运算符可以用来比较基本数据类型和引用...

    Java中的==和equals区别

    - 对于字符串和包装类,应优先使用`equals`方法进行比较,以确保得到正确的结果。 理解`==`与`equals`之间的区别对于编写正确且高效的Java代码至关重要。希望本文能帮助您更好地掌握这一概念,并在实际开发中避免...

    java中==和equals的区别

    对于开发的程序员小伙伴,大家肯定对于==和equals不陌生,而且会经常用到他,那么又有几个能够说清楚了==和equals是怎么回事呢?他了呢两个有什么区别呢? 比较 == 比较的是栈中的值,基本数据类型是变量值,引用...

    ==和equals方法究竟有什么区别

    同时,为了保持一致性,如果重写了`equals()`,通常也需要重写`hashCode()`方法,以满足`equals()`和`hashCode()`的合同约定,即如果两个对象相等(`equals()`返回`true`),它们的`hashCode()`应该也相等。...

    == and equals() 的比较 绝对值得看

    在Java编程语言中,了解`==`和`equals()`的区别是非常关键的,因为它们在处理不同类型的数据时有不同的行为。这两个运算符在比较基本数据类型(如int、char)时表现相同,但当涉及到对象时,它们的行为就有所不同。 ...

    Java中equals,hashcode和==的区别

    "Java中equals、hashcode和==的区别" Java 中 equals、hashcode 和==的区别是 Java 编程语言中一个经常遇到的问题。这三个概念都是用来比较对象的,但是它们之间存在着本质的区别。 首先,==号是Java中的一个...

    ==和equals的比较

    C# 中的 == 和 equals 比较 在 C# 编程语言中,`==` 和 `equals` 是两个常用的比较运算符,但它们之间有很大的区别。 堆和栈的区别 在理解 `==` 和 `equals` 之前,我们需要了解堆和栈的区别。堆是一种动态分配的...

    知识点 比较运算符==和equals方法的比较

    在实践中,还要注意类是否正确地实现了`equals()`和`hashCode()`方法,以确保一致性,特别是当你在处理集合框架中的对象时,如HashSet和HashMap,它们依赖`equals()`和`hashCode()`来确定元素的唯一性。

    java中的==和equals()方法1

    在Java编程语言中,了解如何正确使用`==`和`equals()`方法是非常关键的,因为它们在比较对象和基本类型时有不同的行为。下面将详细解释这两个方法的工作原理、使用场景以及一些常见误区。 首先,`==`运算符主要用于...

    简单概括 ==跟equals的区别

    ==  == :既可以比较基本类型,也可以比较引用类型,如果...hashCode(重写equals就一定要重写hashCode)  没有重写hashCode值不会变,重写了hashCode值就会改变     总结:==跟equals的区别 1. ==既可以比较基本

    java中equals和==的区别

    Java 中 equals 和 == 的区别 Java 中的 equals 和 == 是两个不同的概念,很多开发者容易混淆它们。理解这两个概念的区别是非常重要的,因为它们对编程的正确性和性能都有很大的影响。 首先,我们需要了解 Java ...

    简单介绍java中的“==”和equals

    简单介绍java中的“==”和equals

    hashcode和equals方法

    equals()和hashcode()这两个方法都是从object类中继承过来的。当String 、Math、还有Integer、Double。。。。等这些封装类在使用equals()方法时,已经覆盖了object类的equals()方法.

    Java面试题07.==和equals的区别.mp4

    Java面试题07.==和equals的区别.mp4

    重写equals和hashcode方法_equals_重写equals和hashcode方法_

    在Java编程语言中,`equals()` 和 `hashCode()` 方法是Object类中的两个核心方法,所有类都默认继承自Object类。这两个方法在处理对象比较和集合操作时起着至关重要的作用。当我们创建自定义类并需要对对象进行精确...

    String中==与equals区别验证

    在Java编程语言中,`==` 运算符与 `equals()` 方法被广泛用于比较对象,尤其是当处理字符串...总的来说,`==` 和 `equals()` 在字符串比较中扮演着不同的角色。理解它们的区别对于编写高效且正确的Java程序至关重要。

    java面试题精讲视频MP4Java面试题07.==和equals的区别

    java面试题精讲视频MP4Java面试题07.==和equals的区别提取方式是百度网盘分享地址

    C#中的 == 和equals()区别浅析

    在C#编程语言中,`==`运算符和`Equals()`方法是两种常见的用于比较对象是否相等的方式,但它们之间存在重要的区别。本文将详细解释这两种比较方式的不同点。 首先,`==`运算符主要用于比较基本数据类型的值是否相等...

Global site tag (gtag.js) - Google Analytics