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

Java 最经典面试题:== 和 equals() 到底有什么区别?一文彻底搞懂!

学习 Java 时,几乎每个人都会遇到这样一道经典面试题:

Java 中==equals()有什么区别?

很多初学者都会回答:

==比较地址,equals()比较内容。”

这句话虽然对,但并不完整,甚至在某些情况下还是错的。

今天我们就从零开始,把这个问题彻底讲明白。


一、什么是==

==是 Java 的一个比较运算符

它既可以比较基本数据类型,也可以比较引用类型,但比较规则不同。


1、比较基本数据类型

对于基本数据类型(intdoublecharboolean等),==比较的是值是否相等

例如:

inta=10;intb=10;System.out.println(a==b);

输出:

true

因为:

a 的值:10 b 的值:10

两个值相同,所以返回true

再例如:

doublex=3.14;doubley=3.14;System.out.println(x==y);

结果仍然是:

true

因此:

基本数据类型使用==比较的是值。


2、比较引用类型

对于对象来说,==比较的是两个引用是否指向同一个对象

例如:

Strings1=newString("Java");Strings2=newString("Java");System.out.println(s1==s2);

输出:

false

为什么?

因为内存中实际上创建了两个对象。

堆内存 +-------------+ s1 -->| "Java" | +-------------+ +-------------+ s2 -->| "Java" | +-------------+

虽然内容一样,但它们是两个不同的对象。

所以:

s1 == s2

比较的是:

两个引用是否指向同一个对象?

答案是:

不是

因此返回:

false

所以:

引用类型使用==比较的是对象地址(更准确地说,是比较引用是否指向同一个对象)。


二、什么是equals()

equals()Object类中的一个方法。

源码如下:

publicbooleanequals(Objectobj){return(this==obj);}

可以发现:

Object 默认实现的equals()本质上还是使用==

也就是说:

默认情况下:

obj1.equals(obj2)

等价于:

obj1==obj2

因此:

如果一个类没有重写equals(),那么equals()==的效果完全一样。


三、为什么还要有equals()

因为很多时候,我们更关心的是:

内容是否相同?

而不是:

是不是同一个对象?

例如:

Strings1=newString("Java");Strings2=newString("Java");

虽然:

s1

和:

s2

不是同一个对象。

但是:

字符串内容都是 Java。

这时候:

System.out.println(s1.equals(s2));

输出:

true

为什么?

因为String类重写了equals()方法。

源码思想可以简化理解为:

publicbooleanequals(Objectobj){比较两个字符串长度; 再比较每一个字符; 全部相同返回true}

因此:

"Java" 和 "Java"

内容一样,所以返回:

true

四、什么时候==equals()结果不同?

来看一个经典例子。

Strings1=newString("abc");Strings2=newString("abc");System.out.println(s1==s2);System.out.println(s1.equals(s2));

输出:

false true

为什么?

==

比较的是:

是不是同一个对象?

答案:

不是。

所以:

false

equals()

比较的是:

字符串内容是否相同?

答案:

都是 abc。

所以:

true

这也是 Java 面试最经典的一道题。


五、为什么有时候==又是 true?

例如:

Strings1="Java";Strings2="Java";System.out.println(s1==s2);

输出:

true

很多初学者会疑惑:

不是说==比较地址吗?

为什么这里又是true

原因是:

Java 有字符串常量池(String Pool)

当写:

Strings1="Java";Strings2="Java";

实际上:

字符串常量池 +---------+ | "Java" | +---------+ ↑ ↑ s1 s2

两个变量都指向常量池中的同一个字符串对象。

因此:

s1 == s2

结果就是:

true

如果使用:

newString("Java")

就会重新创建对象。

因此:

Strings1=newString("Java");Strings2=newString("Java");

内存变成:

堆 +--------+ +--------+ | "Java" | | "Java" | +--------+ +--------+ ↑ ↑ s1 s2

自然:

s1 == s2

就是:

false

六、自定义对象为什么 equals() 还是 false?

例如:

classStudent{Stringname;Student(Stringname){this.name=name;}}

创建两个对象:

Students1=newStudent("Tom");Students2=newStudent("Tom");System.out.println(s1.equals(s2));

输出:

false

为什么?

因为:

Student 没有重写equals()

它继承的是:

Object.equals()

而:

Object.equals()

底层就是:

this==obj

比较地址。

因此:

false

七、如何让 equals() 比较内容?

只需要重写equals()

例如:

importjava.util.Objects;classStudent{Stringname;Student(Stringname){this.name=name;}@Overridepublicbooleanequals(Objectobj){if(this==obj){returntrue;}if(obj==null||getClass()!=obj.getClass()){returnfalse;}Studentother=(Student)obj;returnObjects.equals(name,other.name);}}

现在:

Students1=newStudent("Tom");Students2=newStudent("Tom");System.out.println(s1.equals(s2));

输出:

true

因为:

现在比较的是:

name 是否相同。

这也是实际开发中最常见的做法。


八、为什么重写 equals() 通常还要重写 hashCode()?

这是很多面试都会追问的问题。

例如:

HashSet<Student>set=newHashSet<>();

如果:

两个对象:

equals()

返回:

true

但是:

hashCode()

不同。

那么:

HashSet 仍然可能把它们当成两个不同对象。

因此 Java 官方规定:

如果重写了 equals(),通常也必须重写 hashCode(),保证相等对象具有相同的哈希值。

IDE(如 IntelliJ IDEA)通常也会提示同时生成这两个方法。


九、面试怎么回答?

如果面试官问:

Java 中==equals()有什么区别?

可以这样回答:

==是比较运算符。对于基本数据类型,它比较的是值;对于引用类型,它比较的是两个引用是否指向同一个对象。equals()Object类的方法,默认实现也是比较引用,但很多类(例如 String、Integer、自定义实体类)都会重写equals(),用于比较对象内容是否相等。因此,是否比较内容,取决于该类是否重写了equals()方法。

这是比较标准、完整的面试回答。


十、总结

最后用一张表总结:

比较方式基本数据类型引用类型
==比较值比较是否指向同一个对象
equals()不适用(基本类型不能调用方法)默认比较引用;重写后通常比较内容

记住下面四句话即可:

  • ==比较基本类型时比较值。
  • ==比较对象时比较引用是否指向同一个对象。
  • equals()默认和==一样,因为 Object 的实现本质就是==
  • 很多类(如 String)重写了equals(),因此equals()往往用于比较对象内容。

一句话总结:==是 Java 的比较运算符,比较值或对象引用;equals()是对象的方法,默认比较引用,但重写后通常用于比较对象内容是否相等。

http://www.jsqmd.com/news/1187215/

相关文章:

  • 多维聚合实战:维度折叠、TOP-N、稀疏填充与结果结构化
  • 深入解析TSB82AF15-EP OHCI控制器寄存器:从PCIe配置到1394总线调优
  • MSPM0L130x外设深度解析:从窗口看门狗到模拟信号链实战
  • KMS_VL_ALL_AIO智能激活脚本:企业级Windows与Office激活解决方案
  • 从分组到排序:掌握MySQL数据聚合与筛选的完整工作流
  • 如何使用terminal-portfolio快速搭建交互式个人作品集?5分钟入门教程
  • TDES960解串器集线器:多摄像头同步与MIPI CSI-2聚合设计指南
  • 终极免费压缩包密码恢复工具:简单高效的密码测试解决方案
  • 智能周报助手:ModelEngine实现企业办公自动化
  • 5分钟掌握SD-PPP:Photoshop原生AI插件彻底改变你的设计工作流
  • uniapp自定义下拉选择组件:从零封装一个支持搜索与多选的灵活选择器
  • CC2640R2L射频与电气特性深度解析:从参数到实战设计
  • 生产级环境配置:四层隔离与三重锁定实践指南
  • ADP5350与PIC18F45K50构建高效嵌入式电源管理系统
  • Keyboard Chatter Blocker:彻底解决机械键盘连击问题的免费专业工具
  • 【电子元器件篇】1.电阻:从基础参数到实战选型,硬件工程师的避坑指南
  • 革命性抖音批量下载工具:专业级无水印视频采集实战指南
  • 如何解决Windows下LG Ultrafine显示器亮度无法调节的困扰
  • 猫抓浏览器扩展:三分钟掌握网页视频下载终极方案
  • AI驱动的测试报告自动化:技术架构与实施路径
  • Hearthstone-Script:如何用智能脚本彻底解放你的炉石传说游戏时间
  • django-rest-framework-passwordless核心组件揭秘:TokenService如何安全生成与验证一次性令牌
  • 终极Bilibili旧版恢复指南:3分钟找回经典B站体验
  • 如何用Fast-GitHub解决GitHub下载慢问题:3步实现10倍加速
  • YimMenu:GTA5终极安全增强菜单完全指南
  • ChatGPT市场定位困局破解手册(头部AI团队内部未公开的TAM/SAM/SOM三维校准法)
  • FairyGUI Controller实战:5大进阶技巧提升Unity UI开发效率
  • 别急着转行数据岗!先看清这三大‘劝退’真相再决定
  • 3分钟快速上手:FigmaCN中文插件终极使用指南
  • Agent 多租户隔离设计:不同客户的任务别混在同一个上下文里