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

Java 中 == 与 equals() 详解

Java 中 ==equals() 详解

文章目录

  • Java 中 `==` 与 `equals()` 详解
    • 为什么要关注 `==` 和 `equals()`?
    • `==`和`equals`的区别
      • `==`运算符
      • `equals()`方法
      • 关键区别
    • 字符串比较的特殊性
    • 自动装箱与缓存
    • 自定义类中如何正确重写 `equals()`
    • 数组比较是个坑!
    • 编程建议
      • 1. 基本类型 vs 对象类型
      • 2. 字符串比较
      • 3. 自定义类
      • 4. 数组比较
      • 5. 空指针防御
      • 6. 包装类比较
    • 总结

在 Java 编程中,“两个变量相等”这件事并不像表面看起来那么简单。 ==equals() 的行为常常令人迷惑,尤其是在处理字符串、集合、包装类以及自定义对象时。

本文将深入剖析两者的本质区别、使用场景和最佳实践,并带你避开那些常见的坑。


为什么要关注 ==equals()

看下面的例子:

String s1 = new String("hello");
String s2 = new String("hello");System.out.println(s1 == s2);       // false
System.out.println(s1.equals(s2));  // true

两个内容一样的字符串,用 == 得到的是 false,但用 equals() 却是 true。为什么?

再比如:

Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true(意外?)Integer x = 200;
Integer y = 200;
System.out.println(x == y); // false(更意外?)

这类问题在日常写代码中非常常见,理解清楚这两者的机制至关重要。

==equals的区别

==运算符

== 对于基本数据类型和引用类型的作用效果是不同的:

  • 基本数据类型int, char, boolean 等):比较它们的是否相等。
  • 引用类型(如数组、 String, 自定义类等):比较两个对象的内存地址(即是否为同一个对象)。

由于 Java 只有值传递,所以对于 == 来说,不管是比较基本数据类型,还是引用数据类型的变量,其本质比较的都是值,只是引用类型变量存的值是对象的地址。

equals()方法

equals() 不能用于判断基本数据类型的变量,只能用来判断两个对象是否相等。equals()方法存在于Object类中,而Object类是所有类的直接或间接父类,因此所有的类都有equals()方法。

Object类中的equals方法:

public boolean equals(Object obj) {return (this == obj);
}
  • 默认行为(未重写时):Object 类的 equals() 方法内部使用 ==,比较对象的内存地址。
  • 重写后:用于比较对象的内容是否逻辑相等。例如 StringInteger 等类已重写 equals() 方法。

关键区别

特性==equals()
比较对象基本类型值或对象的内存地址对象的内容(需重写方法)
默认行为比较地址Object 类默认比较地址
可自定义不可变可重写以定义逻辑相等

字符串比较的特殊性

  • 直接赋值的字符串(如 String s = "abc")会进入字符串常量池,相同内容的字符串指向同一对象。
  • new String("abc") 会创建新对象,即使内容相同,== 也会返回 false

自动装箱与缓存

详见深入理解Java包装类:自动装箱拆箱与缓存池机制

  • IntegerLong 等包装类在 -128127 范围内会缓存对象,此时 == 可能返回 true

    Integer a = 127;
    Integer b = 127;
    System.out.println(a == b); // true(缓存范围内)Integer c = 128;
    Integer d = 128;
    System.out.println(c == d); // false(超出缓存范围)
    

自定义类中如何正确重写 equals()

  • 如果重写 equals(),必须同时重写 hashCode(),确保两个相等的对象返回相同的哈希码。
  • 否则在使用 HashMapHashSet 等哈希表时会出现逻辑错误。

关于hashCode()的详细内容可以查看:hashCode() 有什么用?

数组比较是个坑!

在 Java 中,数组是一种特殊的对象类型,它用于存储固定数量同类型数据。它继承自 Object 类,且没有重写equals(),因此:==比较两个数组的内存地址(是否为同一个对象),equals()使用的是Object中的默认实现,效果等同于==

内容正确比较方式

使用 Arrays.equals() 方法(一维数组)或 Arrays.deepEquals()(多维数组)

import java.util.Arrays;int[] a = {1, 2, 3};
int[] b = {1, 2, 3};
System.out.println(Arrays.equals(a, b)); // true(内容相同)int[][] arr1 = {{1, 2}, {3, 4}};
int[][] arr2 = {{1, 2}, {3, 4}};
System.out.println(Arrays.deepEquals(arr1, arr2)); // true

编程建议

1. 基本类型 vs 对象类型

  • 基本类型:直接使用 == 比较值。

    int a = 10, b = 10;
    System.out.println(a == b); // true
    
  • 对象类型

    • 判断是否为同一对象:用 ==
    • 判断内容是否相等:用 equals()(需确保已正确重写)。

2. 字符串比较

  • 优先使用 equals():避免依赖字符串常量池。

    String s1 = new String("hello");
    String s2 = "hello";
    System.out.println(s1.equals(s2)); // true
    
  • 空安全比较:将常量放在 equals() 左侧。

    String str = null;
    System.out.println("hello".equals(str)); // false(不会抛异常)
    

3. 自定义类

  • 必须重写 equals()hashCode()

    @Override
    public boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;MyClass obj = (MyClass) o;return Objects.equals(field1, obj.field1) && Objects.equals(field2, obj.field2);
    }@Override
    public int hashCode() {return Objects.hash(field1, field2);
    }
    

4. 数组比较

  • 使用 Arrays.equals()Arrays.deepEquals()

    int[] arr1 = {1, 2, 3};
    int[] arr2 = {1, 2, 3};
    System.out.println(Arrays.equals(arr1, arr2)); // true
    

5. 空指针防御

  • 使用 Objects.equals()

    String s1 = null;
    String s2 = "abc";
    System.out.println(Objects.equals(s1, s2)); // false
    

6. 包装类比较

  • 直接使用 equals():避免依赖缓存机制。

    Integer a = 200, b = 200;
    System.out.println(a.equals(b)); // true
    

总结

  • ==:判断“物理相等”(基本类型值或对象地址)。
  • equals():判断“逻辑相等”(对象内容,需重写方法)。
  • 始终根据需求选择正确的比较方式,并在自定义类中正确实现 equals()hashCode()
http://www.xdnf.cn/news/512983.html

相关文章:

  • 索引与数据结构、并行算法
  • LlamaIndex中应用自定义提示词提升回答质量
  • go语言协程调度器 GPM 模型
  • 华为云Flexus+DeepSeek征文|基于华为云Flexus云服务的Dify 快速构建聊天助手
  • 目标检测新突破:用MSBlock打造更强YOLOv8
  • 如何使用WordPress创建美食博客
  • 跨平台多用户环境下PDF表单“序列号生成的服务器端方案“
  • 如何实现RTSP和RTMP低至100-200ms的延迟:直播SDK的技术突破
  • Metasploit框架与网络安全攻防技术解析
  • 标准库、HAl库和LL库(PC13初始化)
  • 【甲方安全建设】Python 项目静态扫描工具 Bandit 安装使用详细教程
  • 视差场(disparity field)
  • Linux之基础IO
  • MySQL 数据库备份与还原
  • iOS APP启动页及广告页的实现
  • 赋予AI更强的“思考”能力
  • 动态规划(4)可视化理解:图形化思考
  • Tomcat简述介绍
  • 10.8 LangChain三大模块深度实战:从模型交互到企业级Agent工具链全解析
  • 企业级小程序APP用户数据查询系统安全脆弱性分析及纵深防御体系构建
  • JUC入门(二)
  • [创业之路-362]:企业战略管理案例分析-3-战略制定-华为使命、愿景、价值观的演变过程
  • 开源项目实战学习之YOLO11:12.5 ultralytics-models-sam.py通用图像分割模型源码分析
  • Django学习
  • **HTTP/HTTPS基础** - URL结构(协议、域名、端口、路径、参数、锚点) - 请求方法(GET、POST) - 请求头/响应头 - 状态码含义
  • IS-IS 中间系统到中间系统
  • ASCII码表
  • 离散文本表示
  • Java IO框架
  • YOLO12改进-模块-引入Channel Reduction Attention (CRA)模块 降低模型复杂度,提升复杂场景下的目标定位与分类精度