为什么要说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表中取这个对象。这样做的目的是提高取对象的效率。具体过程是这样:

  1. new Object(),JVM根据这个对象的Hashcode值,放入到对应的Hash表对应的Key上,如果不同的对象确产生了相同的hash值,也就是发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同hashcode的对象放到这个单链表上去,串在一起。
  2. 比较两个对象的时候,首先根据他们的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的约定:

    1. 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则对该对象调用hashCode方法多次,它必须始终如一地返回同一个整数。
    2. 如果两个对象根据equals(Object o)方法是相等的,则调用这两个对象中任一对象的hashCode方法必须产生相同的整数结果。
    3. 如果两个对象根据equals(Object o)方法是不相等的,则调用这两个对象中任一个对象的hashCode方法,不要求产生不同的整数结果。但如果能不同,则可能提高散列表的性能。
      根据上一个问题,实际上我们已经能很简单的解释这一点了,比如改写String中的equals为基于内容上的比较而不是内存地址的话,那么虽然equals相等,但并不代表内存地址相等,由hashcode方法的定义可知内存地址不同,没改写的hashcode值也可能不同。所以违背了第二条约定。
      又如new一个对象,再new一个内容相等的对象,调用equals方法返回的true,但他们的hashcode值不同,将两个对象存入HashSet中,会使得其中包含两个相等的对象,因为是先检索hashcode值,不等的情况下才会去比较equals方法的。
    4. 一定要看的干货

深入理解equals和hashCode关系和区别的更多相关文章

  1. 帮助新手理解equals和hashCode

    入行快要两年,偶尔想起来equals和hash还是会有些晕,索性今天就更深入的弄明白一些,不足之处也请各位大神指出批评,共同进步. 刚开始学java的时候只是记忆性的来背,如果一个类在程序中可能进行比 ...

  2. JAVA中用堆和栈的概念来理解equals() "=="和hashcode()

    在学习java基本数据类型和复杂数据类型的时候,特别是equals()"=="和hashcode()部分时,不是很懂,也停留了很长时间,最后终于有点眉目了. 要理解equals() ...

  3. java ==、equals、hashcode有什么区别

    1.== 用来比较两个对象的存储空间 2.equals是Object类提供的方法之一,每个java类都继承Object类,所以每一个对象都具有equals方法,所以在没有覆盖equals方法的情况下, ...

  4. 大杂烩 -- equals、hashCode联系与区别

    基础大杂烩 -- 目录 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Equals 1.默认情况(没有覆盖equals方 ...

  5. "=="、equals、hashCode之间的区别

    1. "=="分为两种情况: (1) 基本数据类型,比较的是其对应的值是否相等: (2) 引用类型,比较的是他们在内存中存放的地址(或者说,是否指向同意对象). 2. equals ...

  6. Java中equals,hashcode,==的区别

    ==  :比较java栈局部变量表中变量的地址或值是否相等. equals : 比较变量的地址在java堆中引用对象是否为同一个对象. hashcode : 通过对象在JVM内存中的存储地址通过特定算 ...

  7. java中equals,hashcode和==的区别

    https://www.cnblogs.com/kexianting/p/8508207.html

  8. ==、equals()、hashcode()的关系和区别

    ==.equals().hashcode()概念 ==:它的作用是判断两个对象的地址是不是相等.即,判断两个对象是不试同一个对象. equals():它的作用也是判断两个对象是否相等.但它一般有两种使 ...

  9. Java == ,equals 和 hashcode 的区别和联系(阿里面试)

    今天阿里的人问我 equals 与hashcode的区别,我答不上来, 仔细查了一下,做了总结: (1) == 这是Java 比较内存地址,就是内存中的对象: java中的==是比较两个对象在JVM中 ...

随机推荐

  1. 13.浏览器屏幕缩放bug修复

    目录 问题:浏览器缩放时,轮播图显示不全,滚动水平滚动条,发现图片缺失 解决:隐藏水平滚动条,页面都只提供垂直滚动条的需求 问题:浏览器缩放时,轮播图显示不全,滚动水平滚动条,发现图片缺失 解决:隐藏 ...

  2. python code practice(二):KMP算法、二分搜索的实现、哈希表

    1.替换空格 题目描述:请实现一个函数,将一个字符串中的每个空格替换成“%20”.例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. 分析: 将长度为 ...

  3. 042.集群网络-flannel及calico

    一 Flannel组件 1.1 flannel介绍 Kubernetes的网络模型假定了所有Pod都在一个可以直接连通的扁平网络空间中.若需要实现这个网络假设,需要实现不同节点上的Docker容器之间 ...

  4. 6. concat_ws用法

    select  CONCAT_WS('-', e.audit_one_name, e.audit_second_name) from t_audit_item_name e  where e.id= ...

  5. SpringBoot集成Swagger(根据源码深入学习Swagger的用法)

    从源码层面讲解Swagger的用法,快速了解掌握Swagger 简介 Swagger 是一个规范且完整的框架,用于生成.描述.调用和可视化 Restful 风格的 Web 服务. 自动生成html文档 ...

  6. MySQL基础知识_1

    平时只会使用简单的增删改查,促使我学习这个来源于一道面试题,左思右想,依然想不出来,所以决定系统的学习一下. MySQL创建数据库 CREATE DATABASE <数据库名>; CREA ...

  7. Diagnostics: File file:/private/tmp/spark-d4ebd819-e623-47c3-b008-2a4df8019758/__spark_libs__6824092999244734377.zip does not exist java.io.FileNotFoundException: File file:/private/tmp/spark-d4ebd819

    spark伪分布式模式 on-yarn出现一下错误 Diagnostics: File file:/private/tmp/spark-d4ebd819-e623-47c3-b008-2a4df801 ...

  8. eNSP之VLAN设计实验

    0.实验目的 1.掌握基于IP地址的VLAN划分: 2.掌握基于交换机端口VLAN划分: 3.通过网关实现不同VLAN间的通讯; 1.实验环境 环境:eNSP模拟器 版本信息:1.3.00.100 V ...

  9. 一书吃透机器学习!新版《机器学习基础》来了,教材PDF、PPT可下载 | 资源

    不出家门,也能学习到国外高校的研究生机器学习课程了. 今天,一本名为Foundations of Machine Learning(<机器学习基础>)的课在Reddit上热度飙升至300, ...

  10. Vue.js系列(一):Vue项目创建详解

    引言 Vue.js作为目前最热门最具前景的前端框架之一,其提供了一种帮助我们快速构建并开发前端项目的新的思维模式.本文旨在帮助大家认识Vue.js,并详细介绍使用vue-cli脚手架工具快速的构建Vu ...