# 📌 深入理解 Java 中的 == 和 equals ()
== 和 equals() 是 Java 面试中最常见但也最容易出错的知识点之一,尤其涉及到字符串、包装类型和对象比较时。本文将全面分析它们的差异,并结合常见陷阱、底层原理和面试追问,为你打下扎实的基础。
# ❓基本区别: == vs equals()
# 🔹 基本数据类型(primitive types)
== :比较的是数值是否相等。
equals() :不可用(会报错)。
# 🔹 引用数据类型(reference types)
== :比较的是内存地址(是否是同一个对象)。
equals() :
- 默认继承自
Object ,也是比较地址;
- 但很多类(如
String , Integer , List )都重写了 equals 方法,用于比较内容。
# 🔍 示例:字符串比较
| String a = new String("hello"); |
| String b = new String("hello"); |
| |
| System.out.println(a == b); |
| System.out.println(a.equals(b)); |
# 🧠 intern () 方法与常量池的作用
| String s1 = new String("hello"); |
| String s2 = "hello"; |
| |
| System.out.println(s1 == s2); |
| System.out.println(s1.intern() == s2); |
# ✨ 解释:
"hello" 是常量池中的字符串;
new String("hello") 会在堆中创建新的对象;
intern() 会返回常量池中的引用。
# 🔗 常见延伸面试题
# ✅ "abc" == "abc" 为何为 true?
两个都是字符串字面量,编译时被优化为常量池的同一引用。
# ✅ new String("abc") == "abc" 为何为 false?
new String("abc") 是堆中新对象;
"abc" 是常量池中的对象;
- 所以
== 比较为 false,地址不同。
# ✅ equals () 与 hashCode () 为什么要同时重写?
Java 容器(如 HashMap)依赖 hashCode 进行定位,equals 判断相等性。
| @Override |
| public boolean equals(Object o) { |
| |
| } |
| @Override |
| public int hashCode() { |
| |
| } |
若只重写 equals,不重写 hashCode,会导致对象相等却存储在不同桶中,行为不一致。
# ✅ Integer a = 128; Integer b = 128; a == b 为何为 false?
Java 对 Integer 做了 值缓存(-128 ~ 127)。超出该范围会 new 新对象:
| Integer x = 127; |
| Integer y = 127; |
| System.out.println(x == y); |
| |
| Integer m = 128; |
| Integer n = 128; |
| System.out.println(m == n); |
# ✅ 如何避免空指针异常判断字符串?
推荐写法:
不推荐写法:
# 🧾 总结归纳
| 比较项 |
基本类型 |
引用类型(==) |
引用类型(equals) |
| 比较内容 |
数值 |
地址(是否是同一对象) |
内容(是否相等) |
| 是否可重写 |
❌ 不适用 |
❌ 不可重写 |
✅ 可自定义逻辑 |
| 使用建议 |
用 == |
判断是否为同一对象 |
判断值是否相等(推荐) |
| 常见陷阱 |
无 |
String、包装类对象 |
需搭配 hashCode 重写 |
# 📂 知识串联:面试问答路径
| └── == 和 equals 区别? |
| ├── "abc" == "abc" |
| ├── new String("abc") == "abc" |
| ├── equals 与 hashCode 的关系? |
| ├── Integer 缓存比较陷阱 |
| └── 字符串 null 判断技巧 |
# 🎯 面试建议
- 遇到引用类型,一律使用
equals() 进行内容比较;
- 包装类型(如 Integer、Boolean)也存在自动装箱带来的引用陷阱;
- 面试时可顺带讲解
intern() 和常量池优化,加分项!