深入理解equals和hashCode关系和区别
直入主题:
很多人把他们放在一起比较,那我们首先要想到的是,他们肯定有大致相同的作用,和一些细小的区别。
先说说他们相同的作用:equals和hashCode方法都是用来判断两个对象的值是否相等,请记住这里说的相等仅仅说的是两个对象的值,和他们的引用无关
区别:
1.他们判断对象相同的方式不一样:
2.他们判断对象是否相等的准确率不一样:
为啥这样说,因为hashCode有极小概率会判断错,而equals的判断结果是百分百正确的
相信看到这里已经有朋友有疑问了,既然hashCode方法不能准确判断,那我们为什么还要用它?哈哈哈,因为我们无法忍受丢弃他的另一个优点,就是效率高,接着往下看,我们慢慢捋一捋。
先说上面的第一点:判断对象的相等的方式不一样
1.equals:重写的equals方法,比如String 的equals方法,如图:
他最终的目的循环判断两个对象的每一个字符是否相等,所有字符全部对应相等,那他们的值肯定也就相等了,这是equals的判断方法
hashCode的判断方法:hashCode是通过用hash算法来计算具体对象实例,得到斌返回一个hashcode值。通过比较hashcode值是否相等来判断两个对象是否相等,
相信大家看到这里是已经有点懵逼了,别急,接下来具体讲讲他的原理:
以java.lang.Object来理解,JVM每new一个Object,它都会将这个Object丢到一个Hash哈希表中去,这样的话,下次做Object的比较或者取这个对象的时候,它会根据对象的hashcode再从Hash表中取这个对象。这样做的目的是提高取对象的效率。具体过程是这样:
- new Object(),JVM根据这个对象的Hashcode值,放入到对应的Hash表对应的Key上,如果不同的对象确产生了相同的hash值,也就是发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同hashcode的对象放到这个单链表上去,串在一起。
- 比较两个对象的时候,首先根据他们的hashcode去hash表中找他的对象,当两个对象的hashcode相同,那么就是说他们这两个对象放在Hash表中的同一个key上,那么他们一定在这个key上的链表上。那么此时就只能根据Object的equal方法来比较这个对象是否equal。当两个对象的hashcode不同的话,肯定他们不能equal.
可能经过上面理论的讲一下大家都迷糊了,我也看了之后也是似懂非懂的。下面我举个例子详细说明下。
list是可以重复的,set是不可以重复的。那么set存储数据的时候是怎样判断存进的数据是否已经存在。使用equals()方法呢,还是hashcode()方法。
假如用equals(),那么存储一个元素就要跟已存在的所有元素比较一遍,比如已存入100个元素,那么存101个元素的时候,就要调用equals方法100次。
但如果用hashcode()方法的话,他就利用了hash算法来存储数据的。
这样的话每存一个数据就调用一次hashcode()方法,得到一个hashcode值及存入的位置。如果该位置不存在数据那么就直接存入,否则调用一次equals()方法,不相同则存,相同不存。这样下来整个存储下来不需要调用几次equals方法,虽然多了几次hashcode方法,但相对于前面来讲效率高了不少。
上面开始的时候我着重说了重写的equals方法,为什么要重写呢?
因为Object的equal方法默认是两个对象的引用的比较,意思就是指向同一内存,地址则相等,否则不相等;如果你现在需要利用对象里面的值来判断是否相等,则重载equal方法。
说道这个地方我相信很多人会有疑问,相信大家都被String对象的equals()方法和"= ="纠结过一段时间,当时我们知道String对象中equals方法是判断值的,而= =是地址判断。
那照这么说equals怎么会是地址的比较呢?
那是因为实际上JDK中,String、Math等封装类都对Object中的equals()方法进行了重写。
我们先看看Object中equals方法的源码:
我们都知道所有的对象都拥有标识(内存地址)和状态(数据),同时“==”比较两个对象的的内存地址,所以说使用Object的equals()方法是比较两个对象的内存地址是否相等,即若object1.equals(object2)为true,则表示equals1和equals2实际上是引用同一个对象。虽然有时候Object的equals()方法可以满足我们一些基本的要求,但是我们必须要清楚我们很大部分时间都是进行两个对象的比较,这个时候Object的equals()方法就不可以了,所以才会有String这些类对equals方法的改写,依次类推Double、Integer、Math。。。。等等这些类都是重写了equals()方法的,从而进行的是内容的比较。希望大家不要搞混了。
改写equals时总是要改写hashcode
java.lnag.Object中对hashCode的约定:
- 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则对该对象调用hashCode方法多次,它必须始终如一地返回同一个整数。
- 如果两个对象根据equals(Object o)方法是相等的,则调用这两个对象中任一对象的hashCode方法必须产生相同的整数结果。
- 如果两个对象根据equals(Object o)方法是不相等的,则调用这两个对象中任一个对象的hashCode方法,不要求产生不同的整数结果。但如果能不同,则可能提高散列表的性能。
根据上一个问题,实际上我们已经能很简单的解释这一点了,比如改写String中的equals为基于内容上的比较而不是内存地址的话,那么虽然equals相等,但并不代表内存地址相等,由hashcode方法的定义可知内存地址不同,没改写的hashcode值也可能不同。所以违背了第二条约定。
又如new一个对象,再new一个内容相等的对象,调用equals方法返回的true,但他们的hashcode值不同,将两个对象存入HashSet中,会使得其中包含两个相等的对象,因为是先检索hashcode值,不等的情况下才会去比较equals方法的。 一定要看的干货
深入理解equals和hashCode关系和区别的更多相关文章
- 帮助新手理解equals和hashCode
入行快要两年,偶尔想起来equals和hash还是会有些晕,索性今天就更深入的弄明白一些,不足之处也请各位大神指出批评,共同进步. 刚开始学java的时候只是记忆性的来背,如果一个类在程序中可能进行比 ...
- JAVA中用堆和栈的概念来理解equals() "=="和hashcode()
在学习java基本数据类型和复杂数据类型的时候,特别是equals()"=="和hashcode()部分时,不是很懂,也停留了很长时间,最后终于有点眉目了. 要理解equals() ...
- java ==、equals、hashcode有什么区别
1.== 用来比较两个对象的存储空间 2.equals是Object类提供的方法之一,每个java类都继承Object类,所以每一个对象都具有equals方法,所以在没有覆盖equals方法的情况下, ...
- 大杂烩 -- equals、hashCode联系与区别
基础大杂烩 -- 目录 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Equals 1.默认情况(没有覆盖equals方 ...
- "=="、equals、hashCode之间的区别
1. "=="分为两种情况: (1) 基本数据类型,比较的是其对应的值是否相等: (2) 引用类型,比较的是他们在内存中存放的地址(或者说,是否指向同意对象). 2. equals ...
- Java中equals,hashcode,==的区别
== :比较java栈局部变量表中变量的地址或值是否相等. equals : 比较变量的地址在java堆中引用对象是否为同一个对象. hashcode : 通过对象在JVM内存中的存储地址通过特定算 ...
- java中equals,hashcode和==的区别
https://www.cnblogs.com/kexianting/p/8508207.html
- ==、equals()、hashcode()的关系和区别
==.equals().hashcode()概念 ==:它的作用是判断两个对象的地址是不是相等.即,判断两个对象是不试同一个对象. equals():它的作用也是判断两个对象是否相等.但它一般有两种使 ...
- Java == ,equals 和 hashcode 的区别和联系(阿里面试)
今天阿里的人问我 equals 与hashcode的区别,我答不上来, 仔细查了一下,做了总结: (1) == 这是Java 比较内存地址,就是内存中的对象: java中的==是比较两个对象在JVM中 ...
随机推荐
- js 随机产生100个0~1000之间的整数
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Ansible Ad-Hoc与常用模块
ansible 执行结果信息–各颜色说明:ansible Ad-Hoc 说明:ansible 如何查看帮助文档与常用模块详解 主机规划 添加用户账号 说明: 1. 运维人员使用的登录账号: 2. 所有 ...
- apply 和 call 方法详解【转载】
本文转载至:http://blog.csdn.net/business122/article/details/8000676 我在一开始看到javascript的函数apply和call时,非常的模糊 ...
- linux环境下安装可操作图库语言Gremlin的图框架HugeGraph
原创/朱季谦 图数据库是一项比较前沿而逐渐热门的技术,是NoSql数据库的一种,它应用图形理论存储实体之间的关系信息,最主要的组成有两种,结点集和连接结点的边.常见的图数据库有Neo4j,Januas ...
- Linux - top命令监控列表的详细解析
统计信息区(系统资源信息区) 前五行,即列表上方的五行 第一行:输出系统任务队列信息 18:46:38:系统当前时间 up 2days 1:54:系统开机后到现在的总运行时间 1 user:当前登录用 ...
- 在ASP.NET MVC中如何预防Cookie的窃取攻击(转载)
Cookie Cookie is a small piece of data sent by a web server to a web browser. The browser stores thi ...
- 原创 记录一次线上Mysql慢查询问题排查过程
背景 前段时间收到运维反馈,线上Mysql数据库凌晨时候出现慢查询的报警,并把原始sql发了过来: --去除了业务含义的sql update test_user set a=1 where id=1; ...
- JWT签发token
目录 一. 认证的发展历程简介 二. JWT签发Token源码分析 2.1 JWT工作原理及简介 2.2 JWT生成token源码分析 返回目录 一. 认证的发展历程简介 这里真的很简单的提一下认证的 ...
- 封装WebSocket(建立链接、主动关闭)
一.前言 近期项目里需做一个在线聊天功能,就想要在对话的时候建立socket链接.又因为聊天只是其中一个部分,在它外面还有一些全局的消息通知需要接收,因此也需要建立socket链接.在该项目里不仅一处 ...
- 记录一些服务端术语和搭建web服务器
菜单快捷导航 服务端常用术语 搭建web服务器和配置虚拟主机 记录一些服务端方面的常用术语 1.CS架构和BS架构 1.1 CS架构 CS(Client/Server),基于安装包类型的桌面或手机软件 ...