当前位置: 首页 > news >正文

Java中的equals()与==的区别与用法

1. 区别

  • “==”操作符用于比较两个对象的地址是否相等。
  • .equals() 方法用于比较两个对象的内容是否相等。

Object 类的 .equals() 方法默认采用的是“”操作符进行比较。假如子类没有重写该方法的话,那么“”操作符和 .equals() 方法的功效就完全一样——比较两个对象的内存地址是否相等。

但实际情况中,有不少类重写了 .equals() 方法,因为比较内存地址的要求比较严格,不太符合现实中所有的场景需求。拿 String 类来说,我们在比较字符串的时候,的确只想判断它们俩的内容是相等的就可以了,并不想比较它们俩是不是同一个对象。

况且,字符串有字符串常量池的概念,本身就推荐使用 String s = “字符串” 这种形式来创建字符串对象,而不是通过 new 关键字的方式,因为可以把字符串缓存在字符串常量池中,方便下次使用,不用遇到 new 就在堆上开辟一块新的空间。

2. .equals()源码

public boolean equals(Object anObject) {if (this == anObject) {return true;}if (anObject instanceof String) {String aString = (String)anObject;if (coder() == aString.coder()) {return isLatin1() ? StringLatin1.equals(value, aString.value): StringUTF16.equals(value, aString.value);}}return false;
}

首先,如果两个字符串对象的可以“==”,那就直接返回 true 了,因为这种情况下,字符串内容是必然相等的。否则就按照字符编码进行比较,分为 UTF16 和 Latin1,差别不是很大,就拿 Latin1 的来说吧。

@HotSpotIntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {if (value.length == other.length) {for (int i = 0; i < value.length; i++) {if (value[i] != other[i]) {return false;}}return true;}return false;
}

这个 JDK 版本是 Java 17,也就是最新的 LTS(长期支持)版本。该版本中,String 类使用字节数组实现的,所以比较两个字符串的内容是否相等时,可以先比较字节数组的长度是否相等,不相等就直接返回 false;否则就遍历两个字符串的字节数组,只有有一个字节不相等,就返回 false。

这是 Java 8 中的 equals 方法源码:

public boolean equals(Object anObject) {// 判断是否为同一对象if (this == anObject) {return true;}// 判断对象是否为 String 类型if (anObject instanceof String) {String anotherString = (String)anObject;int n = value.length;// 判断字符串长度是否相等if (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;// 判断每个字符是否相等while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false;
}

JDK 8 比 JDK 17 更容易懂一些:首先判断两个对象是否为同一个对象,如果是,则返回 true。接着,判断对象是否为 String 类型,如果不是,则返回 false。如果对象为 String 类型,则比较两个字符串的长度是否相等,如果长度不相等,则返回 false。如果长度相等,则逐个比较每个字符是否相等,如果都相等,则返回 true,否则返回 false。
“如果要进行两个字符串对象的内容比较,除了 .equals() 方法,还有其他两个可选的方案。”

1)Objects.equals()

Objects.equals() 这个静态方法的优势在于不需要在调用之前判空。

public static boolean equals(Object a, Object b) {return (a == b) || (a != null && a.equals(b));
}

如果直接使用 a.equals(b),则需要在调用之前对 a 进行判空,否则可能会抛出空指针 java.lang.NullPointerException。Objects.equals() 用起来就完全没有这个担心。

Objects.equals("小萝莉", new String("小" + "萝莉")) // --> true
Objects.equals(null, new String("小" + "萝莉")); // --> false
Objects.equals(null, null) // --> trueString a = null;
a.equals(new String("小" + "萝莉")); // throw exception

2)String 类的 .contentEquals()

.contentEquals() 的优势在于可以将字符串与任何的字符序列(StringBuffer、StringBuilder、String、CharSequence)进行比较。

public boolean contentEquals(CharSequence cs) {// Argument is a StringBuffer, StringBuilderif (cs instanceof AbstractStringBuilder) {if (cs instanceof StringBuffer) {synchronized(cs) {return nonSyncContentEquals((AbstractStringBuilder)cs);}} else {return nonSyncContentEquals((AbstractStringBuilder)cs);}}// Argument is a Stringif (cs instanceof String) {return equals(cs);}// Argument is a generic CharSequenceint n = cs.length();if (n != length()) {return false;}byte[] val = this.value;if (isLatin1()) {for (int i = 0; i < n; i++) {if ((val[i] & 0xff) != cs.charAt(i)) {return false;}}} else {if (!StringUTF16.contentEquals(val, cs, n)) {return false;}}return true;
}

从源码上可以看得出,如果 cs 是 StringBuffer,该方法还会进行同步,非常的智能化;如果是 String 的话,其实调用的还是 equals() 方法。当然了,这也就意味着使用该方法进行比较的时候,多出来了很多步骤,性能上有些损失。

同样来看一下 JDK 8 的源码:

public boolean contentEquals(CharSequence cs) {// argument can be any CharSequence implementationif (cs.length() != value.length) {return false;}// Argument is a StringBuffer, StringBuilder or Stringif (cs instanceof AbstractStringBuilder) {char v1[] = value;char v2[] = ((AbstractStringBuilder)cs).getValue();int i = 0;int n = value.length;while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}// Argument is a Stringif (cs.equals(this))return true;// Argument is a non-String, non-AbstractStringBuilder CharSequencechar v1[] = value;int i = 0;int n = value.length;while (n-- != 0) {if (v1[i] != cs.charAt(i))return false;i++;}return true;
}

同样更容易理解一些:首先判断参数长度是否相等,不相等则返回 false。如果参数是 AbstractStringBuilder 的实例,则取出其 char 数组,遍历比较两个 char 数组的每个元素是否相等。如果参数是 String 的实例,则直接调用 equals 方法比较两个字符串是否相等。如果参数是其他实现了 CharSequence 接口的对象,则遍历比较两个对象的每个字符是否相等。

相关文章:

Java中的equals()与==的区别与用法

1. 区别 “”操作符用于比较两个对象的地址是否相等。.equals() 方法用于比较两个对象的内容是否相等。 Object 类的 .equals() 方法默认采用的是“”操作符进行比较。假如子类没有重写该方法的话&#xff0c;那么“”操作符和 .equals() 方法的功效就完全一样——比较两个对…...

【ai】 2005年 rule based expert system学习笔记1

PPT 是2005年的? Negnevitsky, Pearson Education 使用两种推理引擎的选择 backward chaining(逆向链接)推理过程 backward chaining(逆向链接)推理过程的GPT解释 这幅图展示了一个基于规则的专家系统如何通过backward chaining(逆向链接)推理过程来达到最终的推理目标…...

AI写作|去除了AI味道,我还花2分钟动手制作了一个coze智能体

本文背景&#xff1a; AI写出来的东西&#xff0c;机器味太浓&#xff1f; AI生成的文章内容质量不稳定、因为依赖于已有的数据和模式&#xff0c;AI可能很难创作出具有深度见解或独创性的内容 AI还无法完全理解复杂的上下文关系&#xff0c;导致生成的内容与用户期望的上下文不…...

数据集相关类代码回顾理解 | utils.make_grid\list comprehension\np.transpose

目录 utils.make_grid list comprehension np.transpose utils.make_grid x_gridutils.make_grid(x_grid, nrow4, padding2) make_grid 函数来自torchvision的utils模块&#xff0c;用于图像数据可视化&#xff0c;将一批图像排列成一个网格。 x_grid&#xff1a;四维图像…...

React前端面试每日一试 3.状态(State)和属性(Props)的区别是什么?

加粗样式先简单介绍一下Props和State的特点 Props&#xff08;属性&#xff09; Props&#xff08;Properties&#xff09;是React组件间传递数据的一种方式。它们是从父组件传递给子组件的只读数据&#xff0c;子组件不能修改这些数据。Props主要用于配置组件&#xff0c;使…...

射灯怎么安装才好看,射灯安装防踩坑

射灯安装的5个尺寸,不懂容易踩坑      你得选好角度,算好安装距离      为了防止我们花了钱却装不出效果      1,射灯是可以调角度的,一般选24度和36度就行      像小的装饰画可以选24度,大的装饰画选36度      也就是重点照明选24,洗墙和打造小山丘36度  …...

Mojo变量详解

变量是一个保存值或对象的名称。Mojo中的所有变量都是可变的 - 它们的值可以改变。(如果您想定义一个在运行时无法更改的常量值,请参见alias关键字。) Mojo曾经支持使用let关键字来声明不可变变量。为了简化语言,并出于其他原因,已经将其移除 ( 为何移除let)。为了简化…...

ElasticSearch 面试题及答案整理,最新面试题

Elasticsearch中的倒排索引是什么?它如何工作? 倒排索引是Elasticsearch中用于快速全文搜索的关键数据结构。它的工作原理包括: 1、索引创建: 对文档中的每个唯一单词创建一个索引条目。 2、文档列表: 每个索引条目都指向包含该单词的文档列表。 3、快速查找: 在搜索时,…...

Java基本语法学习的案例练习

本文是在学习过C语言后&#xff0c;开始进行Java学习时&#xff0c;对于基本语法的一些案例练习。案例内容来自B站黑马编程课 1.HelloWorld 问题介绍;请编写程序输出“HelloWorld”. public class HelloWorld { public static void main(String[] args) { System.out.print…...

FPGA实现LCD12864控制

目录 注意&#xff01; a) 本工程采用野火征途PRO开发板&#xff0c;外接LCD12864部件进行测试。 b) 有偿提供代码&#xff01;&#xff01;&#xff01;可以定制功能&#xff01;&#xff01;&#xff01;有需要私信&#xff01;&#xff01;&#xff01; c) 本文测试采用…...

mysql 批量执行sql语句脚本

有时候我们需要批量执行多个数据库的创建和数据创建执行可以通过下面脚本批量创建和执行脚本。我们只需要在sql命令行或者客户端执行下面一个脚本批量创建执行多个库的创建和执行 xxxxinit.sql create user root% identified by test; mysql -h 192.168.17.7 -u root -p mysq…...

餐饮连锁加盟的网页UI,如果不大气,谁能相信你的品牌力

...

【Git】Git概述

一、Git的基本概念和特点 基本概念&#xff1a; 仓库&#xff08;Repository&#xff09;&#xff1a;Git存储代码的基本单位&#xff0c;包含项目的所有文件和历史提交记录。Git支持本地仓库和远程仓库&#xff0c;本地仓库存储在开发者的计算机上&#xff0c;而远程仓库通常…...

【图解网络】学习记录

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 TCP/IP 网络模型有哪几层&#xff1f;键入网址到网页显示&#xff0c;期间发生了什么&#xff1f;Linux 系统是如何收发网络包的&#xff1f;NAPIHTTP 是什么&#…...

【Vulnhub系列】Vulnhub_Seattle_003靶场渗透(原创)

【Vulnhub系列靶场】Vulnhub_Seattle_003靶场渗透 原文转载已经过授权 原文链接&#xff1a;Lusen的小窝 - 学无止尽&#xff0c;不进则退 (lusensec.github.io) 一、环境准备 1、从百度网盘下载对应靶机的.ova镜像 2、在VM中选择【打开】该.ova 3、选择存储路径&#xff0…...

java: 错误: 无效的源发行版:17

错误现象&#xff1a; java: 错误: 无效的源发行版&#xff1a;17 背景&#xff1a;在配置一个springboot项目时候&#xff0c;报出这个错误&#xff0c;错误提示信息很简单&#xff0c;很模糊。 排查&#xff1a;百度后&#xff0c;推测大概率就是pom文件的配置问题&#xf…...

【Python机器学习】k-近邻算法简单实践——识别手写数字

为了简化理解&#xff0c;需要识别的数字已经使用图形处理软件&#xff0c;处理成具有相同的色彩和大小32*32的黑白图像&#xff0c;并转换成文本格式 准备数据&#xff1a;将图像转换为测试向量 实际图像存储在trainingDigits的2000个例子和testDigits中的900个测试数据 我们…...

Linux源码阅读笔记14-IO体系结构与访问设备

IO体系结构 与外设通信通常称为输入输出&#xff0c;一般缩写为I/O。在实现外设IO的时候&#xff0c;内核必须处理三个可能出现的问题&#xff1a; 必须根据具体的设备类型和模型&#xff0c;使用各种方法对硬件寻址。内核必须向用户应用程序和系统工具提供访问各种设备的方法…...

只出现一次的数字-位运算

题目描述&#xff1a; 个人题解&#xff1a; 代码实现&#xff1a; class Solution { public:int singleNumber(vector<int>& nums) {int ret 0;for (auto e: nums) ret ^ e;return ret;} };复杂度分析&#xff1a; 时间复杂度&#xff1a;O(n)&#xff0c;其中 n…...

pyqt designer使用spliter

1、在designer界面需要使用spliter需要父界面不使用布局&#xff0c;减需要分割两个模块选中&#xff0c;再点击spliter分割 2、在分割后&#xff0c;再对父界面进行布局设置 3、对于两边需要不等比列放置的&#xff0c;需要套一层 group box在最外层进行分割...

ARGUS:视觉中心化多模态推理框架,实现像素级可验证Chain-of-Thought

1. 项目概述&#xff1a;这不是又一个“多模态大模型”&#xff0c;而是一次视觉推理范式的重新校准ARGUS这个名字&#xff0c;乍看像某个军事侦察系统代号&#xff0c;其实它精准指向了当前多模态AI领域最棘手的痛点——视觉信息在推理链中长期处于“失语”状态。你肯定见过这…...

端侧AI平民化:轻量专家模型+动态调度实现千元机本地大模型推理

1. 项目概述&#xff1a;这不是又一个“AI手机App”&#xff0c;而是一次对算力平民化的重新定义 “Enter Project Gecko: AI in Your Pocket, Without the Premium Price Tag”——这个标题里没有一个生僻词&#xff0c;但每个词都在精准刺向当前AI消费端的痛点。我做终端AI落…...

Linux驱动开发:proc接口原理、实现与调试实战

1. 项目概述&#xff1a;为什么需要了解proc接口&#xff1f;在Linux驱动开发这条路上&#xff0c;很多开发者朋友都曾有过这样的困惑&#xff1a;我的驱动模块加载成功了&#xff0c;设备也识别了&#xff0c;但怎么才能直观地看到它内部的工作状态、配置参数&#xff0c;或者…...

Stata面板数据回归保姆级教程:从xtset到豪斯曼检验,手把手搞定实证分析

Stata面板数据回归实战指南&#xff1a;从数据准备到模型选择的完整解析 面板数据分析在经济学、管理学等社科领域占据着核心地位&#xff0c;但许多初学者在面对Stata操作时常常感到无从下手。本文将从一个完整的实证分析流程出发&#xff0c;不仅介绍基础命令&#xff0c;更着…...

从0到就业,学习网络安全的正确顺序

从0到就业&#xff0c;学习网络安全的正确顺序 想入行网络安全&#xff0c;别怕&#xff0c;这条路虽然看起来复杂&#xff0c;但只要找对方法&#xff0c;就能少走很多弯路。核心原则就是&#xff1a;先学基础&#xff0c;再学安全&#xff0c;动手永远比光看重要 一、入门基…...

服务间鉴权的方式

服务间鉴权的方式1. API Key&#xff08;静态密钥&#xff09;Java 中如何生成随机数&#xff1a;什么是 LCG&#xff1f;/dev/random 和 /dev/urandom 详解1. Math.random() —— 绝对禁用2. java.util.Random —— 明文禁止&#xff08;安全场景&#xff09;3. java.security…...

【扣子coze教程】0成本搭建自动生成公众号的飞书智能体(附实战工作流)

今天教大家0成本搭建自动生成公众号的飞书智能体&#xff0c;并部署至飞书。话不多说&#xff0c;咋们直接开始~ 1. 采集网站文章的工作流 如下是完整的工作流1.1 登录多维飞书表格 创建url、title、content、new_content列&#xff0c;为后续保存位置做准备其中url用以存放网页…...

JMeter分布式压测原理与高可用集群搭建实战

1. 为什么单台JMeter跑不出真实流量——分布式压测不是“加机器”那么简单 你有没有试过用Jmeter对一个新上线的订单服务做压测&#xff0c;本地配了200个线程&#xff0c;结果TPS卡在80就上不去了&#xff0c;CPU才用了35%&#xff0c;网络IO几乎为零&#xff1f;我第一次遇到…...

火狐渗透插件实战指南:15款专业工具高效赋能Web侦察与漏洞验证

1. 这不是普通浏览器插件合集&#xff0c;而是渗透测试人员的“外挂式侦察兵” 很多人第一次看到“火狐插件做渗透测试”这个说法&#xff0c;第一反应是&#xff1a;浏览器插件能干啥&#xff1f;改个User-Agent&#xff1f;抓个Cookie&#xff1f;顶多算个辅助小工具。我2016…...

拒绝玩具CRUD:用 5 款全栈离线“仓储管理”微系统精通前后端解耦(附专家级级联 Prompt)

各位全栈同仁、大前端极客以及正在突破技术瓶颈的开发者们&#xff0c;大家好。作为一名每天和分布式架构、数据库事务以及前端复杂状态流打交道的工程师&#xff0c;今天想和大家聊聊全栈工程落地中的“咬合力”。在很多技术社区里&#xff0c;大家往往能看到各种速成的单表 C…...