Java 中的 == 运算符、equals 方法和 hashcode 方法
一、== 运算符
== 是 Java 中的一个运算符,用于比较两个对象,但在比较两个对象的时候需要根据比较类型分情况进行讨论。
1.1 基本数据类型与基本数据类型
基本数据类型之间通过 == 进行比较的时候,是直接比较它们的大小,而与它们的具体类型无关。
short num1 = 20000;
int num2 = 20000;
System.out.println(num1 == num2); // Output: true
1.2 引用类型与引用类型
引用类型之间是比较它们的内存地址,因此两个同类型的对象通过 == 进行比较时的结果一般为 false。
public class Test {public static void main(String[] args) {Obj o1 = new Obj();Obj o2 = new Obj();System.out.println(o1 == o2); // Output: false}
}class Obj {}
但也不是所有情况都会返回 false,基本数据类型的引用类型有个常量池的机制,使得它们就算是两个对象,依然会指向同一片内存空间,也就是说,它们依然是同一个对象。
Integer num1 = 100, num2 = 100;
System.out.println(num1 == num2); // Output: true
具体内容请见:八大基本类型及其包装类型
1.3 基本数据类型与引用类型
当基本数据类型与引用类型之间进行比较时,若引用类型是数字类的,那么就可以进行比较,其他类型的无法进行比较,会报错。
Integer num1 = 200;
int num2 = 200;
System.out.println(num1 == num2); // Output: trueint num = 200;
String str = "123";
System.out.println(str == num); // Error: 二元运算符 '==' 的操作数类型错误
二、equals 方法
equals 是 Java 引用类型的一个基本方法,在没有对其进行重写(override)的情况下,equals 方法默认是比较两个对象的内存地址,重写之后视具体情况而定。
String str1 = "1";
String str2 = "2";
System.out.println(str1.equals(str2)); // Output: false
2.1 equals 方法和 == 运算符的区别
- == 是一个运算符,equals 是对象的方法(所以基本数据类型没有);
- == 在比较基本数据类型时,是比较的值,比较对象的时候,是比较其内存地址;
- equals 默认(没有被重写)是比较对象的内存地址,重写后是其他的内容(如 String 就是其对象所表示内容的值)
三、hashcode 方法
hashcode 是一个非常特殊的方法,它涉及到散列表的知识,哈希(hash)翻译过来就是散列的意思,它是一种算法,可以快速将任意对象转换为一个 16 进制的数值,而不同的对象之间,通过哈希算法得到的哈希值大概率是不会相同的,有极小概率会相同,此时就出现了一种被称为“哈希冲突”的情况,这里我们不对其做深究,具体内容请参见:哈希算法
总之,在没有出现“哈希冲突”的情况下,我们就可以通过不同对象的哈希值不相同这一特性来判断两个对象是否为同一对象。
String str1 = "1";
String str2 = "2";
System.out.println(str1.hashCode() == str2.hashCode()); // Output: false
当然,一般情况下我们是不会像上面这样用 hashcode 这一方法的,因为无法保证不会出现“哈希冲突”的情况。虽然不同对象的哈希值有可能相同,但是两个对象的哈希值的不同则说明它们一定不相同!因此,哈希值可以用于判断两个对象是否不等。
四、区别和联系
4.1 区别
== 一般用来判断数字是否相等,equals 一般用来判断两个对象是否相等,而 hashcode 一般用来判断两个对象是否不等。
== 只比较数字,判断速度最快,此外是 hashcode 方法,因为哈希值的计算十分快速,最后是 equals,默认情况下 equals 是比较两个对象的内存地址,这一过程虽然很快速,但更一般的情况是 equals 方法被重写了,比较的是两个非数字类型对象的属性值,因此它最慢。
String str1 = "1";
String str2 = "1";
System.out.println(str1.equals(str2)); // Output: true
上面的代码中,Java 内置引用类型 String 就重写了 equals 方法,它比较的是两个 String 对象的内容,而非内存地址。
4.2 联系
== 一般和 equals 和 hashcode 扯不上什么关系,从某种角度上来说,equals 和 hashcode 之间也没有必然联系。但是 Java 中存在一种数据结构,将 equals 和 hashcode 联系了起来,那就是 HashMap 及其子类。
HashMap 中键是不可以重复的,因此它的键就必须是不同的对象,那么这个时候就先用计算速度快的 hashcode 进行比较,若哈希值都不相等,那么这两个对象必然不相等,若是相等的,那么这个就有两种可能出现,一种情况是这两个对象是真的相等,另外一种情况就是出现了罕见的“哈希冲突”现象,那么这个时候就轮到 equals 来进行判断了!这样一来,就高效且快速地解决了键不可重复的问题。
从上面 HashMap 的比较中我们也可以看到,当我们自定义类型的时候,若要重写 equals 方法或者 hashcode 方法,请将它们两个同时进行重写,因为 Java 内置数据结构 HashMap 等判断键是否重复是需要同时调用它们两个。
综上,我们可以总结为下表:
| 比较方式 | == 运算符 | equals 方法 | hashcode 方法 |
| 比较速度 | 快速 | 默认情况下快速,一般情况下缓慢 | 中等 |
| 比较值 | 数值 | 默认是内存地址,一般是对象属性 | 哈希值 |
4.3 经典问题
为什么重写了 hashcode 方法还要重写 equals 方法?如果只重写 equals 方法而不重写 hashcode 方法会有问题吗?在 HashMap 中怎样体现出来的?
在 HashMap 中,键是不可以重复的,也就是说,它们的键都是不相同的,因此就要判断不同对象是否为同一对象。为了解决这个问题,HashMap 中同时调用了对象的 equals 方法和 hashcode 方法来进行判断。判断的部分源代码是这样的:
if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))return e;
hashcode 方法和 equals 方法都可以用来比较两个对象,但是二者有一些区别:
| 比较方式 | equals 方法 | hashcode 方法 |
| 比较速度 | 默认情况比较内存地址,速度快; 重写后一般比较内容,速度慢 | 计算哈希值,速度快 |
| 比较值 | 内存地址或者内容(属性) | 哈希值 |
因此先用计算速度快的 hashcode 进行比较,这可以解决大部分问题,但由于可能出现“哈希冲突”,于是还需要 equals 方法解决。
正因为在判断键是否重复这一问题需要同时调用 equals 方法和 hashcode 方法,故我们自己定义的类中重写它们时必须两个一起重写。若只重写 equals 方法,而不重写 hashcode 方法,那么创建两个内容一样但内存地址不同的对象并存储在 HashMap 中时,会被当成两个键,而不是一个键,进而引发其他错误。
相关文章:
Java 中的 == 运算符、equals 方法和 hashcode 方法
一、 运算符 是 Java 中的一个运算符,用于比较两个对象,但在比较两个对象的时候需要根据比较类型分情况进行讨论。 1.1 基本数据类型与基本数据类型 基本数据类型之间通过 进行比较的时候,是直接比较它们的大小,而与它们的具体…...
第一个ArkTS项目实践-鸿蒙ArkTS
第一个ArkTS项目实践-ArkTS 第一个ArkTS项目实践-ArkTS自定义组件的组成配置属性与布局配置属性布局 改变组件状态循环渲染列表数据代码ToDoItem组件ToDoList页面 效果参考资料 第一个ArkTS项目实践-ArkTS 本篇文章是官网上视频对ArkTS开发实践的第一个视频,主要是引…...
【数据结构•堆】序列和的前n小元素(堆排序)
题目描述 问题:序列和的前 n n n小元素 给出两个长度为 n n n的有序表 A A A和 B B B, 在A和B中各任取一个, 可以得到 n 2 n^2 n2 个和. 求这些和最小的 n n n个。 输入输出格式 输入格式: 输入数据共三行。 第一行,一个整数值 n n …...
Keepalived+http高可用实战
环境准备: 两台安装了keepalived的服务器 ip:192.168.134.170;192.168.134.172 1、安装http服务 yum install httpd -y2、写一个测试页面 [rootlocalhost ~]# echo "hostname -I,web1 test page. " > /var/www/html/inde [rootlocalho…...
Linux文件系统管理
Linux文件系统管理 磁盘的组成与分区 计算机用于存取文件的硬件是磁盘,磁盘的组成主要有磁盘盘、机械手臂、磁盘读取头与主轴马达所组成, 而数据的写入其实是在磁盘盘上面。磁盘盘上面又可细分出扇区(Sector)与磁道(Track)两种单位, 其中扇区…...
MyBatis-Plugin源码全面分析
三、MyBatis-Plugin 1. 基本开发方式 需求:在MyBatis执行之前打印一行醒目的日志,携带参数 实现Interceptor接口: Intercepts(Signature(type Executor.class,method "query",args {MappedStatement.class,Object.class, RowB…...
Vscode 常用操作教程
一、语言换成中文 这是我们可以直接点击左边栏第四个图标搜索插件 chinese ,也可以直接ctrlshiftp快捷键也会出来如图所示图标,出来chinese 插件之后选择安装install,安装完成之后重新ctrlshiftp会出现如图所示页面 找到我的鼠标在的地方对应的中文,此时…...
Linux设备树详解
Linux 设备树详解 Linux 操作系统早期是针对个人电脑设备而开发的操作系统,而个人电脑处理器产商较为单一(例如只有 Intel,AMD)同时个人电脑产商均使用 Intel 或 AMD 制造的处理器,业界形成了统一的总线/硬件接口标准…...
.netcore grpc服务端流方法详解
一、服务端流式处理概述 客户端向服务端发送请求,服务端可以将多个消息流式传输回调用方和客户端流相反,客户端流发出请求,服务端可以传输一批消息给客户端,直至本次请求响应完全结束。针对文件分段传输下载,该方式非…...
python爬虫数据解析xpath、jsonpath,bs4
数据的解析 解析数据的方式大概有三种 xpathJsonPathBeautifulSoup xpath 安装xpath插件 打开谷歌浏览器扩展程序,打开开发者模式,拖入插件,重启浏览器,ctrlshiftx,打开插件页面 安装lxml库 安装在python环境中的Scri…...
go语言的database/sql结合squirrel工具sql生成器完成数据库操作
database/sql database/sql是go语言内置数据库引擎,使用sql查询数据库,配置datasource后使用其数据库操作方法对数据库操作,如下: package mainimport ("database/sql""fmt"_ "github.com/Masterminds…...
LVS集群和分布式
LVS 一.集群和分布式概念 1.1 集群 在计算机领域,集群早在 1960 年就出现,随着互联网和计算机相关技术的发展,现在 集群这一技术已经在各大互联网公司普及。 1.1.1 集群概念 计算机集群指一组通过计算机网络连接的计算机,它们…...
使用QT可视化设计对话框详细步骤与代码
一、创建对话框基本步骤 创建并初始化子窗口部件把子窗口部件放到布局中设置tab键顺序建立信号-槽之间的连接实现对话框中的自定义槽 首先前面三步在这里是通过ui文件里面直接进行的,剩下两步则是通过代码来实现 二、项目创建详细步骤 创建新项目 为项目命名 为…...
TFTP Server
简介 TFTP(Trivial File Transfer Protocol,简单文件传输协议)是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。端口号为69。 TFTP和FTP的区别 安全性区别 FTP支持登录安全&…...
登录验证码实现
Hutool代码改造 Hutool 有参考文档;很多工具类;把一些功能都封装好;都不用你自己去写;直接调用它的工具类 它这里会详细告诉你引入方式Hutool <dependency><groupId>cn.hutool</groupId><artifactId>hu…...
2. 获取自己CSDN文章列表并按质量分由小到大排序(文章质量分、博客质量分、博文质量分)(阿里云API认证)
文章目录 写在前面步骤打开CSDN质量分页面粘贴查询文章url按F12打开调试工具,点击Network,点击清空按钮点击查询是调了这个接口https://bizapi.csdn.net/trends/api/v1/get-article-score用postman测试调用这个接口(不行,认证不通…...
在Windows和MacOS环境下实现批量doc转docx,xls转xlsx
一、引言 Python中批量进行办公文档转化是常见的操作,在windows状态下我们可以利用changeOffice这个模块很快进行批量操作。 二、在Windows环境下的解决文案 Windows环境下,如何把doc转化为docx,xls转化为xlsx? 首先ÿ…...
【网络编程(二)】NIO快速入门
NIO Java NIO 三大核心组件 Buffer(缓冲区):每个客户端连接都会对应一个Buffer,读写数据通过缓冲区读写。Channel(通道):每个channel用于连接Buffer和Selector,通道可以进行双向读…...
【Vue-Router】嵌套路由
footer.vue <template><div><router-view></router-view><hr><h1>我是父路由</h1><div><router-link to"/user">Login</router-link><router-link to"/user/reg" style"margin-left…...
MySQL索引总结
MySQL索引总结 1.索引的概念、作用与使用场景 本质上就是减少读写磁盘的次数。 索引是一种特殊的文件,包含这对数据表中所有记录的引用指针,可以对表中的一列或多列创建索引,并指定索引的类型,每种类型都有对应数据结构实现。 …...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
在树莓派上添加音频输入设备的几种方法
在树莓派上添加音频输入设备可以通过以下步骤完成,具体方法取决于设备类型(如USB麦克风、3.5mm接口麦克风或HDMI音频输入)。以下是详细指南: 1. 连接音频输入设备 USB麦克风/声卡:直接插入树莓派的USB接口。3.5mm麦克…...
vue3 daterange正则踩坑
<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...
从物理机到云原生:全面解析计算虚拟化技术的演进与应用
前言:我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM(Java Virtual Machine)让"一次编写,到处运行"成为可能。这个软件层面的虚拟化让我着迷,但直到后来接触VMware和Doc…...
【深度学习新浪潮】什么是credit assignment problem?
Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...
【Kafka】Kafka从入门到实战:构建高吞吐量分布式消息系统
Kafka从入门到实战:构建高吞吐量分布式消息系统 一、Kafka概述 Apache Kafka是一个分布式流处理平台,最初由LinkedIn开发,后成为Apache顶级项目。它被设计用于高吞吐量、低延迟的消息处理,能够处理来自多个生产者的海量数据,并将这些数据实时传递给消费者。 Kafka核心特…...
