Java 中 == 与 equals() 的区别
1. 一句话总结
==:基本类型比数值;引用类型比地址(判断是否指向堆中同一个对象)。equals():是一个方法。默认实现(Object类)也是比地址;但String、包装类等通过重写实现了内容/逻辑相等的比较。
Java 中 == 运算符与 equals() 方法的区别。== 用于基本类型比较数值,引用类型比较内存地址;equals() 默认比较地址,但可重写以比较内容。文章涵盖字符串常量池、包装类缓存机制、equals/hashCode 契约、重写规则及 null 安全写法。建议基本类型用 ==,对象内容比较用 equals,枚举比较推荐用 ==。
== 与 equals() 的区别==:基本类型比数值;引用类型比地址(判断是否指向堆中同一个对象)。equals():是一个方法。默认实现(Object 类)也是比地址;但 String、包装类等通过重写实现了内容/逻辑相等的比较。核心金句:== 判断'是不是同一个';equals() 判断'长得像不像'(取决于是否重写)。
| 特性 | == | equals() |
|---|---|---|
| 本质 | Java 运算符 | Object 类的方法 |
| 比较内容 | 基本类型比数值,引用类型比内存地址 | 默认比地址,重写后比对象内容 |
| 可定制性 | 不可重写,行为固定 | 可以重写,自定义逻辑相等规则 |
| 适用范围 | 任何基本类型或对象引用 | 仅限对象(不能用于基本类型) |
| null 处理 | null == null 为 true | null.equals(...) 会抛 NPE |
== 的用法int a = 10;
int b = 10;
System.out.println(a == b); // true
char c1 = 'A';
char c2 = 'B';
System.out.println(c1 == c2); // false
String s1 = new String("Java");
String s2 = new String("Java");
String s3 = s1;
System.out.println(s1 == s2); // false(不同对象)
System.out.println(s1 == s3); // true(同一引用)
equals() 的用法Object.equals() 等同于 ==public boolean equals(Object obj) {
return (this == obj);
}
String 重写了 equals(),比较字符串内容:
String s1 = new String("Java");
String s2 = new String("Java");
System.out.println(s1.equals(s2)); // true
面试常考:为什么 a == b 有时是 true,有时是 false?
String a = "abc";
String b = "abc";
String c = new String("abc");
System.out.println(a == b); // true(常量池同一对象)
System.out.println(a == c); // false(new 在堆上创建新对象)
System.out.println(a.equals(c)); // true(内容相等)
补充:
String d = c.intern();
System.out.println(a == d); // true(intern 返回常量池引用)
Integer、Short、Byte、Character、Long(部分范围)存在缓存机制。
Integer x = 127;
Integer y = 127;
Integer m = 128;
Integer n = 128;
System.out.println(x == y); // true (缓存 -128~127)
System.out.println(m == n); // false (超出缓存范围)
System.out.println(m.equals(n)); // true
结论:比较包装类型的值,优先用 equals()(或拆箱成基本类型再比 ==,注意 null 拆箱会 NPE)。
equals() 与 hashCode() 的契约(HashMap/HashSet 面试点)equals() 为 true,那么它们的 hashCode()必须相同。HashMap/HashSet 的基本流程:先 hashCode() 定位桶,再 equals() 精确比较。equals() 不重写 hashCode():可能出现'放得进去、取不出来'或'重复放入'的问题。equals() 正确重写规则(契约)x.equals(x) 必须为 true。x.equals(y) 为 true 则 y.equals(x) 也为 true。x.equals(y)、y.equals(z) 为 true 则 x.equals(z) 必须为 true。x.equals(null) 必须为 false。instanceof 还是 getClass()?(加分点)getClass():要求必须同一具体类才相等,更严格,较不易破坏对称性。instanceof:允许子类参与比较,更灵活,但继承体系下容易破坏对称性/传递性。null 安全:避免 NPE 的写法(实用)String s = null;
System.out.println(s.equals("a")); // NPE
String s = null;
System.out.println("a".equals(s)); // false
或:
System.out.println(java.util.Objects.equals(s, "a")); // false(null-safe)
import java.util.Objects;
public class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
==?什么时候用 equals()?(面试收尾)==。==。equals()(并确保类正确重写 equals/hashCode)。enum:推荐使用 ==(枚举天然单例,且语义明确)。StringBuilder / StringBuffer 的 equals():没有重写,仍是地址比较;要比内容用 toString()。equals():数组没有重写 equals(),比较地址;比内容用 Arrays.equals() / Arrays.deepEquals()。== 可能因精度误差不可靠,业务上常用误差范围(epsilon)比较。
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online