本文目录导读:

这是一个非常经典的 Java 面试题,也是初学者容易混淆的核心概念,用一个具体的案例来解释,确实是最直观的方式。
我们先直接看案例,然后再总结原理。
案例代码
public class EqualsAndDoubleEqual {
public static void main(String[] args) {
// ---------- 场景 1: 基本数据类型 ----------
int a = 10;
int b = 10;
System.out.println("基本类型 int 比较: " + (a == b));
// 输出: true (比较值)
// ---------- 场景 2: 引用类型 - 字符串字面量 ----------
String s1 = "hello";
String s2 = "hello";
System.out.println("字符串字面量 == 比较: " + (s1 == s2));
// 输出: true (因为字符串常量池,s1和s2指向同一个对象)
System.out.println("字符串字面量 equals 比较: " + s1.equals(s2));
// 输出: true (比较内容)
// ---------- 场景 3: 引用类型 - new 创建的不同字符串对象 ----------
String s3 = new String("hello");
String s4 = new String("hello");
System.out.println("new String == 比较: " + (s3 == s4));
// 输出: false (s3和s4是堆中两个不同的对象,内存地址不同)
System.out.println("new String equals 比较: " + s3.equals(s4));
// 输出: true (String的equals方法被重写,比较的是字符内容)
// ---------- 场景 4: 引用类型 - 自定义类 (未重写equals) ----------
Person p1 = new Person("张三", 20);
Person p2 = new Person("张三", 20);
System.out.println("自定义类 == 比较: " + (p1 == p2));
// 输出: false (两个不同对象,地址不同)
System.out.println("自定义类 equals 比较 (未重写): " + p1.equals(p2));
// 输出: false (Object的equals默认也是比较地址,所以为false)
// ---------- 场景 5: 引用类型 - 自定义类 (重写equals) ----------
PersonWithEquals p3 = new PersonWithEquals("李四", 25);
PersonWithEquals p4 = new PersonWithEquals("李四", 25);
System.out.println("重写equals类 == 比较: " + (p3 == p4));
// 输出: false (依然是两个不同对象)
System.out.println("重写equals类 equals 比较: " + p3.equals(p4));
// 输出: true (我们重写了equals,比较的是name和age的内容)
}
}
// 辅助类1:没有重写equals
class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
}
// 辅助类2:重写了equals
class PersonWithEquals {
String name;
int age;
PersonWithEquals(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true; // 如果指向同一个对象,直接返回true
if (obj == null || getClass() != obj.getClass()) return false;
PersonWithEquals that = (PersonWithEquals) obj;
return age == that.age && name.equals(that.name); // 比较核心属性
}
}
运行结果
基本类型 int 比较: true
字符串字面量 == 比较: true
字符串字面量 equals 比较: true
new String == 比较: false
new String equals 比较: true
自定义类 == 比较: false
自定义类 equals 比较 (未重写): false
重写equals类 == 比较: false
重写equals类 equals 比较: true
| 比较方面 | (双等号) | .equals() |
|---|---|---|
| 适用于基本类型 | ✅ 比较的是数值是否相等 | ❌ 不能用于基本类型 |
| 适用于引用类型 | ✅ 比较的是内存地址 (是否指向同一个对象) | ✅ 默认比较地址,但通常重写后比较内容 |
| String类的默认行为 | 比较地址 (但字面量复用常量池) | ✅ 已重写,比较字符串内容 |
| 是否可自定义 | 不能 (Java语法固定) | 可以 (在自定义类中重写该方法,实现自己的比较逻辑) |
关键图解 (以 new String() 为例)
内存堆:
s3 ------> [ 字符串对象 "hello" ] (地址 0x100)
s4 ------> [ 字符串对象 "hello" ] (地址 0x200)
s3 == s4 => false (因为 0x100 != 0x200,比较的是地址)
s3.equals(s4) => true (因为 String的equals方法会逐字符对比: 'h'='h', 'e'='e', ...)
几点补充说明
- 基本类型没有
equals方法:int a = 10; a.equals(b);这种写法会编译报错。 - String 的 有时为 true:就像案例中的
s1 == s2,这是因为 JVM 的字符串常量池机制,直接用双引号"hello"创建的字符串,JVM 会先在常量池查找,如果已有就直接复用,s1和s2指向的是同一个对象, 返回 true,但new String("hello")一定会创建新对象, 返回 false。 - 重写 equals 必须重写 hashCode:这是 Java 的约定。
p3.equals(p4)返回 true,那么它们的hashCode()也应该相同,否则在HashMap、HashSet等集合中会出现逻辑错误,IDE (如 IDEA, Eclipse) 可以自动生成这两个方法。
简单一句话概括:
- 比的是“是不是同一个人” (地址/值)。
equals(重写后) 比的是“人身上的内容是不是一样” (属性内容)。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播