在 Java 中,== 和 equals() 都用于比较对象,但它们的行为和用途有显著的区别。以下是它们的详细对比:
1. == 运算符
== 是 Java 中的 比较运算符,用于比较两个对象的 引用 或 基本数据类型的值。
1.1 比较基本数据类型
当用于基本数据类型(如 int、char、boolean 等)时,== 比较的是它们的 值。
int a = 5;
int b = 5;
System.out.println(a == b); // true,因为值相同
1.2 比较对象引用
当用于对象时,== 比较的是两个对象的 引用(即内存地址),而不是对象的内容。
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1 == str2); // false,因为引用不同
2. equals() 方法
equals() 是 Object 类中定义的方法,用于比较两个对象的 内容。默认情况下,equals() 的行为与 == 相同,但可以通过重写 equals() 方法来实现自定义的比较逻辑。
2.1 默认行为
Object 类中的 equals() 方法实现如下:
public boolean equals(Object obj) {
return (this == obj);
}
2.2 重写 equals()
大多数 Java 类(如 String、Integer、ArrayList 等)都重写了 equals() 方法,以比较对象的内容。
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1.equals(str2)); // true,因为内容相同
2.3 自定义 equals()
如果需要比较自定义对象的内容,可以重写 equals() 方法。例如:
class Person {
String name;
int age;
@Override
public boolean equals(Object obj) {
if (this == obj) return true; // 如果是同一个对象
if (obj == null || getClass() != obj.getClass()) return false; // 如果对象为空或类型不同
Person person = (Person) obj; // 类型转换
return age == person.age && Objects.equals(name, person.name); // 比较内容
}
}
3. == 和 equals() 的区别
|
特性 | == | equals() |
|---|---|---|
| 比较对象 | 比较对象的引用(内存地址) | 比较对象的内容(可重写) |
| 基本数据类型 | 比较值 | 不能用于基本数据类型 |
| 默认行为 | 比较引用 | 比较引用(除非被重写) |
| 适用场景 | 判断两个对象是否是同一个实例 | 判断两个对象的内容是否相同 |
4. 示例对比
4.1 字符串比较
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1 == str2); // false,引用不同
System.out.println(str1.equals(str2)); // true,内容相同
4.2 整数比较
Integer a = new Integer(5);
Integer b = new Integer(5);
System.out.println(a == b); // false,引用不同
System.out.println(a.equals(b)); // true,内容相同
4.3 自定义对象比较
Person p1 = new Person("Alice", 25);
Person p2 = new Person("Alice", 25);
System.out.println(p1 == p2); // false,引用不同
System.out.println(p1.equals(p2)); // true,内容相同(如果重写了 equals())
5. 注意事项
5.1 重写 equals() 时必须重写 hashCode():
如果两个对象 equals() 返回 true,它们的 hashCode() 必须相同。
这是为了确保对象在哈希表(如 HashMap)中正常工作。
规则说明
规则 1:如果两个对象 equals() 返回 true,它们的 hashCode() 必须相同。
原因:哈希表(如 HashMap)依赖 hashCode() 来确定对象的存储位置。如果两个对象 equals() 返回 true,但 hashCode() 不同,哈希表可能会将它们存储在不同的位置,导致查找失败或行为异常。
规则 2:如果两个对象 equals() 返回 false,它们的 hashCode() 可以相同,也可以不同。
原因:如果对象的 hashCode() 值发生变化,哈希表可能无法正确找到对象。
规则 3:hashCode() 的值在对象的生命周期内必须保持一致。
原因:哈希表允许哈希冲突(即不同的对象具有相同的哈希值),并通过链表或红黑树等机制处理冲突。
5.1.1 为什么需要同时重写 equals() 和 hashCode()?
哈希表(如 HashMap)通过以下步骤存储和查找对象:
调用 hashCode() 计算对象的哈希值,确定存储位置(桶)。
如果多个对象具有相同的哈希值(哈希冲突),使用 equals() 比较对象内容,找到匹配的对象。
如果仅重写 equals() 而不重写 hashCode(),可能会导致以下问题:
查找失败:两个对象 equals() 返回 true,但 hashCode() 不同,哈希表会将它们存储在不同的位置,导致查找失败。
行为异常:哈希表无法正确存储或查找对象,导致程序行为不符合预期。
5.1.2 未重写 hashCode() 的问题示例
class Person {
String name;
int age;
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return age == person.age && Objects.equals(name, person.name);
}
// 未重写 hashCode()
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person("Alice", 25);
Person p2 = new Person("Alice", 25);
System.out.println(p1.equals(p2)); // true
HashMap<Person, String> map = new HashMap<>();
map.put(p1, "Alice");
System.out.println(map.get(p2)); // null,因为 p1 和 p2 的 hashCode() 不同
}
}
5.1.3 如何正确重写 hashCode()?
使用 Objects.hash()
Objects.hash() 是一个工具方法,可以方便地计算哈希值。它会将传入的参数组合成一个哈希值。
@Override
public int hashCode() {
return Objects.hash(name, age);
}
手动实现 hashCode()
如果不想使用 Objects.hash(),可以手动实现 hashCode()。例如:
@Override
public int hashCode() {
int result = 17; // 初始值
result = 31 * result + (name == null ? 0 : name.hashCode()); // 31 是常用的质数
result = 31 * result + age;
return result;
}
5.2 避免空指针异常:
- 使用
equals()时,建议将常量或已知非空的对象放在前面。例如: -
"hello".equals(str); // 推荐 str.equals("hello"); // 不推荐,如果 str 为 null 会抛出异常
5.3 == 用于枚举比较:
- 枚举类型(
enum)的实例是单例的,可以使用==进行比较。
6. 总结
==:比较基本数据类型的值或对象的引用。equals():比较对象的内容(默认比较引用,可重写)。- 根据具体需求选择合适的比较方式,并注意重写
equals()和hashCode()的一致性。
Java中==和equals的区别详解
8万+

被折叠的 条评论
为什么被折叠?



