【Java】==和equals的区别

在 Java 中,== 和 equals() 都用于比较对象,但它们的行为和用途有显著的区别。以下是它们的详细对比:

1. == 运算符

== 是 Java 中的 比较运算符,用于比较两个对象的 引用 或 基本数据类型的值

1.1 比较基本数据类型

当用于基本数据类型(如 intcharboolean 等)时,== 比较的是它们的 

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 类(如 StringIntegerArrayList 等)都重写了 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() 的一致性。
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值