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.索引的概念、作用与使用场景 本质上就是减少读写磁盘的次数。 索引是一种特殊的文件,包含这对数据表中所有记录的引用指针,可以对表中的一列或多列创建索引,并指定索引的类型,每种类型都有对应数据结构实现。 …...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
起重机起升机构的安全装置有哪些?
起重机起升机构的安全装置是保障吊装作业安全的关键部件,主要用于防止超载、失控、断绳等危险情况。以下是常见的安全装置及其功能和原理: 一、超载保护装置(核心安全装置) 1. 起重量限制器 功能:实时监测起升载荷&a…...
算法刷题-回溯
今天给大家分享的还是一道关于dfs回溯的问题,对于这类问题大家还是要多刷和总结,总体难度还是偏大。 对于回溯问题有几个关键点: 1.首先对于这类回溯可以节点可以随机选择的问题,要做mian函数中循环调用dfs(i&#x…...