equals和==有什么区别?

面试题目

  • ==和equals有什么区别?
  • 这两个都适用于哪些场景进行比较?
  • 为什么重写了equals方法,还必须重写hashcode方法?

这个问题基本上在各面试题库中都会有出现,也是现实项目中使用比较多的一个比较,面试的时候问的也比较多,下面从源码结合案例进行学习,不光会用,还要学会思考为什么用?

题目解析

==和equals有什么区别?

在Object类中,其equals的方法底层实现就是"=="来实现的,下面查看一下Object对象的源码:

public boolean equals(Object obj) {return (this == obj);
}

也就是说,对于 Object 对象来说,equals 和 == 都是一样的,都是比较对象的引用是否相同

但是,在JDK中的其他类中通常会重写 equals 以实现具体的值比较,例如 Integer、String、Double等都重写了equals。比如String的equals被重写后,比较的是字符值。

如下源码所示。 Integer 中的 equals 实现源码如下:

    public boolean equals(Object obj) {if (obj instanceof Integer) {return value == ((Integer)obj).intValue();}return false;}

从上述源码可以看出,Integer 中会先将 Integer 对象转换成基础类型int值来进行比较,所以此时就不再是对比两个对象的引用了,而是对比两个对象的值是否相等。

再来看一下String中的 equals 实现源码如下:

public boolean equals(Object anObject) {// this代表当前类(String)调用equals方法的对象。//this对象将与传入的参数对象anObject比较内存值是否一样,如果一样,返回trueif (this == anObject) {return true;}//使用instanceof关键字 判断传入的参数的类型是不是String类型的实例。if (anObject instanceof String) {//如果判断出传入的参数的类型是String类型,把传入的参数强转为String类型String anotherString = (String)anObject;//value是类中字符数组的名字,通过value.length获得字符数组的长度//String的底层是由char类型的数组实现的。int n = value.length;//比较类中字符数组的长度与传入的参数对象中的字符数组长度是否一样if (n == anotherString.value.length) {//如果长度一样//使用v1[]存储value的字串char v1[] = value;//使用v2[]存储传入的参数中value的字串char v2[] = anotherString.value;//使用循环比较v1[] 和 v2[] 对应位置的字符是否相同。int i = 0;while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}//如果两个字符数组的长度不一致,返回falsereturn false;
}

从 String 中的 equals 中可以看出,它和 Integer 一样,是将 Object 中的引用比较重写成了值比较了。

适用于哪些场景进行比较

所以,对于 Object 来说,== 和 equals 都是一样的,都是用来对比两个对象的引用是否相同的,而其他 Java 中的类中,如 String 或 Integer 等,通常都会重写 equals 让其变为比较具体的值是否相同,而非引用是否相同。 所以,我们通常会使用 == 来对比两个对象的引用是否相同,而使用 equals 对比两个值是否相同(前提条件是重写了 equals 方法)。

另外重写了equlas后,也必须重写hashcode()方法

为什么重写了equals方法,还必须重写hashcode方法

  1. 为了提高效率

采取重写hashcode方法,先进行hashcode比较,如果不同,那么就没必要在进行equals的比较了,这样就大大减少了equals比较的次数,这对比需要比较的数量很大的效率提高是很明显的,一个很好的例子就是在集合中的使用。

例如:Java中的List集合是有序的,因此是可以重复的。

而set集合是无序的,因此是不能重复的,那么怎么能保证不能被放入重复的元素呢,但靠equals方法一样比较的话,如果原来集合中有10000个元素,那么在放入第10001个元素的时候,难道要将前面的所有元素都进行比较,看看是否有重复,这个效率可想而知,因此hashcode就应遇而生了,java就采用了hash表,利用哈希算法(也叫散列算法),就是将对象数据根据该对象的特征使用特定的算法将其定义到一个地址上,那么在后面定义进来的数据只要看对应的hashcode地址上是否有值,那么就用equals比较,如果没有则直接插入,只要就大大减少了equals的使用次数,执行效率就大大提高了。

  1. 为了保证同一个对象

保证在equals相同的情况下hashcode值必定相同,如果重写了equals而未重写hashcode方法,可能就会出现两个没有关系的对象equals相同的(因为equal都是根据对象的特征进行重写的),但hashcode确实不相同的。

hash类存储结构(HashSet、HashMap等等)添加元素会有重复性校验,校验的方式就是先取hashCode判断是否相等(找到对应的位置,该位置可能存在多个元素),然后再取equals方法比较(极大缩小比较范围,高效判断),最终判定该存储结构中是否有重复元素。

重写后equals和hashcode两个方法的关系

  1. equals()相等的两个对象,hashcode()一定相等。
  2. hashcode()不等,一定能推出equals()也不等。
  3. hashcode()相等,equals()可能相等,也可能不等。

所以先进行hashcode()判断,不等就不用equals()方法了。

案例说明

现在来定义一个类,然后想和 Integer 或 String 中的 equals 一样,用其对比值而非引用是否相同的实现代码如下:

@Data
public class Book {private String name;private int num;@Overridepublic boolean equals(Object obj) {if (this == obj) {return true;}if (obj == null || getClass() != obj.getClass()) {return false;}Book book = (Book) obj;return this.name.equals(book.name) && this.num == book.num;}/*** 根据重写的 equals() 方法中用于比较的字段(num 和 name)来计算对象的哈希码。* 通过使用质数 31 这样的系数乘积,可以更好地分散哈希码,减少哈希冲突的可能性。* @return*/@Overridepublic int hashCode() {int result = 17;result = 31 * result + num;result = 31 * result + (name != null ? name.hashCode() : 0);return result;}
}

总结

对于 Object 来说,equals 是用 == 实现的,所以二者是相同的,都是用来比较两个对象的引用是否相同的,但 Java 中的其他类,都会重写 equals 让其变为值比较,而非引用比较,如 Integer 和 String 都是这样。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/2528.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用html画一个四叶草

<!DOCTYPE html> <html lang"en" > <head> <meta charset"UTF-8"> <title>四叶草</title> <link href"" rel"stylesheet"> <link rel"stylesheet" href"css/style.css&q…

数字逻辑电路基础-有限状态机

文章目录 一、有限状态机基本结构二、verilog写一个基础有限状态机(moore型状态机)三、完整代码一、有限状态机基本结构 本文主要介绍使用verilog编写有限状态机FSM(finite state machine),它主要由三部分组成,下一状态逻辑电路,当前状态时序逻辑电路和输出逻辑电路。 有…

更易使用,OceanBase开发者工具 ODC 4.2.4 版本升级

亲爱的朋友们&#xff0c;大家好&#xff01;我们的ODC&#xff08;OceanBase Developer Center &#xff09;再次迎来了重要的升级V 4.2.4&#xff0c;这次我们诚意满满&#xff0c;从五个方面为大家精心打造了一个更加易用、贴心&#xff0c;且功能更强的新版本&#xff0c;相…

SAP Fiori开发中的JavaScript基础知识15 - 原型,object,constructor,class,继承

1. 前言 本文将介绍JavaScript中的核心概念 - 原型&#xff0c;并会介绍基于原型的应用场景object&#xff0c;constructor&#xff0c;class&#xff0c;继承。 本文会将这几个核心概念汇总在一篇博客中&#xff0c;因为这些概念是触类旁通的&#xff0c;希望对你有帮助。 …

RTU遥测终端为城市排水安全保驾护航!

近年来&#xff0c;全球气候变迁与城市化进程不断加速&#xff0c;导致强降雨事件频发&#xff0c;道路低洼地带、下穿式立交桥和隧道等区域在暴雨中常易积水&#xff0c;严重阻碍了人民的出行&#xff0c;甚至危及生命与财产安全。而传统的排水管网管理方式已难以适应现代城市…

STM32 学习13 低功耗模式与唤醒

STM32 学习13 低功耗模式与唤醒 一、介绍1. STM32低功耗模式功能介绍2. 常见的低功耗模式&#xff08;1&#xff09;**睡眠模式 (Sleep Mode)**:&#xff08;2&#xff09;**停止模式 (Stop Mode)**:&#xff08;3&#xff09;**待机模式 (Standby Mode)**: 二、睡眠模式1. 进入…

docker swoole+php8.2

安装 docker pull phpswoole/swoole:php8.2-alpine docker run --rm phpswoole/swoole:php8.2-alpine php -m docker run --rm phpswoole/swoole:php8.2-alpine php --ri swoole docker run --rm phpswoole/swoole:php8.2-alpine composer --version #换阿里composer源 docker…

SystemServer启动SystemUI

SystemServer启动SystemUI&#xff1a; private static void startSystemUi(Context context, WindowManagerService windowManager) {PackageManagerInternal pm LocalServices.getService(PackageManagerInternal.class);Intent intent new Intent();intent.setComponent(p…

BBS前后端混合项目--01

总路由 # urls.py """BBS1 URL ConfigurationThe urlpatterns list routes URLs to views. For more information please see:https://docs.djangoproject.com/en/3.2/topics/http/urls/ Examples: Function views1. Add an import: from my_app import views2…

related_name和related_query_name属性

在Django模型继承中&#xff0c;假如在外键或多对多字段中使用了related_name属性或related_query_name属性&#xff0c;则必须为该字段提供一个独一无二的反向名字和查询名字。但是&#xff0c;这样在抽象基类中一般会引发问题&#xff0c;因为基类中的字段都被子类继承并且保…

LightGBM原生接口和Sklearn接口参数详解

LightGBM原生接口和Sklearn接口参数详解 数据科学&#xff1a;Scipy、Scikit-Learn笔记超参数调优&#xff1a;网格搜索&#xff0c;贝叶斯优化&#xff08;optuna&#xff09;详解XGBoost原生接口和Sklearn接口参数详解LightGBM一、Sklearn风格接口lightgbm.LGBMRegressor参数…

初见-响应式编程-002

&#x1f917; ApiHug {Postman|Swagger|Api...} 快↑ 准√ 省↓ GitHub - apihug/apihug.com: All abou the Apihug apihug.com: 有爱&#xff0c;有温度&#xff0c;有质量&#xff0c;有信任ApiHug - API design Copilot - IntelliJ IDEs Plugin | Marketplace #Reacti…

BERT-CRF 微调中文 NER 模型

文章目录 数据集模型定义数据集预处理BIO 标签转换自定义Dataset拆分训练、测试集 训练验证、测试指标计算推理其它相关参数CRF 模块 数据集 CLUE-NER数据集&#xff1a;https://github.com/CLUEbenchmark/CLUENER2020/blob/master/pytorch_version/README.md 模型定义 imp…

【iOS开发】(五)react Native路由和导航20240421-22

【iOS开发】(五)react Native 路由和导航Navigation 20240421 在&#xff08;一&#xff09;&#xff08;二&#xff09;中我们 Reactnative搭建了开发环境、学习了 基础语法、状态管理&#xff0c;JSX、组件、状态和生命周期以及样式布局等。 在&#xff08;三&#xff09;&a…

MATLAB 数据类型

MATLAB 数据类型 MATLAB 不需要任何类型声明或维度语句。每当 MATLAB 遇到一个新的变量名&#xff0c;它就创建变量并分配适当的内存空间。 如果变量已经存在&#xff0c;那么MATLAB将用新内容替换原始内容&#xff0c;并在必要时分配新的存储空间。 例如&#xff0c; Tota…

Vue3中使用无缝滚动插件vue3-seamless-scroll

官网&#xff1a;https://www.npmjs.com/package/vue-seamless-scroll 1、实现效果文字描述&#xff1a; 表格中的列数据进行横向无缝滚动&#xff0c;某一列进行筛选的时候&#xff0c;重新请求后端的数据&#xff0c;进行刷新 2、安装&#xff1a;npm i vue3-seamless-scrol…

Pytorch:Dataset类和DataLoader类

文章目录 一、Dataset 类1、定义2、示例 二、DataLoader 类1、定义2、参数3、示例&#xff1a;使用 DataLoader 三、总结四、实战1、load_data函数&#xff1a;2、IrisDataset类3、DataLoader 的使用 在机器学习和深度学习框架中&#xff0c;尤其是在 PyTorch 中&#xff0c;Da…

小程序 rich-text 解析富文本 图片过大时如何自适应?

在微信小程序中&#xff0c;用rich-text 解析后端返回的数据&#xff0c;当图片尺寸太大时&#xff0c;会溢出屏幕&#xff0c;导致横向出现滚动 查看富文本代码 图片是用 <img 标签&#xff0c;所以写个正则匹配一下图片标签&#xff0c;手动加上样式即可 // content 为后…

Python 面向对象——5.多态

本章学习链接如下&#xff1a; Python 面向对象——1.基本概念 Python 面向对象——2.类与对象实例属性补充解释&#xff0c;self的作用等 Python 面向对象——3.实例方法&#xff0c;类方法与静态方法 Python 面向对象——4.继承 1.基本概念 多态是面向对象编程&#x…

kafka架构

kafka架构 Kafka是一种分布式流处理平台&#xff0c;由Apache软件基金会开发。它采用发布-订阅模式&#xff0c;可以持久化和高效地处理大规模数据流。 Kafka的架构主要由以下几个组成部分&#xff1a; Producer&#xff08;生产者&#xff09;&#xff1a;发送数据到Kafka集…