在 Java 中,== 和 equals() 是用于比较对象 / 值的两种核心方式,但本质和适用场景截然不同,以下从底层原理、使用场景、典型示例三方面详细解析:
一、==:比较的是 "值" 或 "内存地址"
== 是运算符,其比较规则取决于操作数的类型:
1. 基本数据类型(byte/short/int/long/float/double/char/boolean)
直接比较值是否相等(无需关注内存地址)。
示例:
int a = 10;
int b = 10;
System.out.println(a == b); // true(值相等)
char c1 = 'A';
char c2 = 65; // 'A'的ASCII码是65
System.out.println(c1 == c2); // true(值相等)
2. 引用数据类型(类 / 接口 / 数组 / String 等)
比较对象的内存地址是否相同(即是否为同一个对象)。
示例:
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2); // false(两个不同对象,地址不同)
String s3 = "hello";
String s4 = "hello";
System.out.println(s3 == s4); // true(字符串常量池复用,地址相同)
User u1 = new User("张三");
User u2 = u1; // u2指向u1的地址
System.out.println(u1 == u2); // true(同一对象)
二、equals():比较的是 "对象的内容是否相等"
equals() 是Object 类的方法 ,默认实现等价于==(比较地址),但可被子类重写以实现 "内容比较"。
1. Object 类的默认实现
public boolean equals(Object obj) {
return (this == obj); // 本质是==,比较地址
}
2. 子类重写equals()的典型场景
-
String 类:重写后比较字符串的字符序列是否相同。
-
示例:
String s1 = new String("hello"); String s2 = new String("hello"); System.out.println(s1.equals(s2)); // true(内容相同) -
包装类(Integer/Boolean 等):重写后比较数值是否相同。
-
示例:
Integer i1 = new Integer(100); Integer i2 = new Integer(100); System.out.println(i1.equals(i2)); // true(数值相同) -
自定义类 :需手动重写
equals()以比较对象属性。示例(User 类重写equals()):class User { private String name; private int age; // 构造方法、getter/setter省略 @Override public boolean equals(Object o) { if (this == o) return true; // 地址相同直接返回true if (o == null || getClass() != o.getClass()) return false; // 类型不同返回false User user = (User) o; return age == user.age && Objects.equals(name, user.name); // 比较属性 } } // 使用 User u1 = new User("张三", 20); User u2 = new User("张三", 20); System.out.println(u1.equals(u2)); // true(属性相同)
三、== vs equals() 核心区别表
| 特性 | == |
equals() |
|---|---|---|
| 本质 | 运算符 | Object 类的方法(可重写) |
| 基本类型比较 | 比较值 | 不适用(基本类型无equals()) |
| 引用类型比较 | 比较内存地址(是否同一对象) | 默认比较地址,重写后比较内容 |
| 适用场景 | 基本类型值比较、引用地址比较 | 引用类型内容比较 |
四、常见坑点与注意事项
-
String 的
==陷阱:- 字符串字面量(
"hello")会存入常量池 ,相同字面量复用地址,==返回 true; new String("hello")会创建新对象(堆内存),即使内容相同,==返回 false。
- 字符串字面量(
-
包装类的缓存机制:
- Integer 对
-128~127的数值缓存,Integer i1=100; Integer i2=100;用==返回 true;超出范围则返回 false(需用equals())。
- Integer 对
-
自定义类未重写
equals():直接使用equals()等价于==,需手动重写(结合Objects.equals()避免空指针)。 -
null 值比较:
-
==可直接比较 null(如obj == null); -
equals()调用前需判空(否则空对象调用会抛NullPointerException):String s = null; System.out.println(s.equals("hello")); // 报错NullPointerException System.out.println("hello".equals(s)); // false(安全写法)
-
五、总结
- 基本类型比较 :用
==; - 引用类型内容比较 :用
equals()(确保子类已重写); - 引用地址比较 :用
==; - 字符串比较 :优先用
equals(),避免==的常量池陷阱。
记住核心逻辑:==看 "地址 / 值",equals()看 "内容"(重写后)。