java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > java   ==、equals () 与 hashCode ()

一文读懂 Java 中的 ==、equals () 与 hashCode ()原理与避坑指南

作者:凛冬君主

在 Java 开发中,==、equals() 和 hashCode() 是处理对象比较和哈希计算的核心元素,理解它们之间的区别与联系对编写高质量代码至关重要,本文给大家介绍Java 中的 ==、equals()与hashCode()原理,感兴趣的朋友一起看看吧

在 Java 开发中,==、equals() 和 hashCode() 是处理对象比较和哈希计算的核心元素,理解它们之间的区别与联系对编写高质量代码至关重要。

一、== 运算符

== 是 Java 中的比较运算符,用于比较两个值是否相等,其行为取决于比较的是基本类型还是引用类型:

1. 比较基本数据类型

对于 int、double、char 等基本类型,== 比较的是实际存储的值:

int a = 10;
int b = 10;
System.out.println(a == b); // true,值相等
double c = 3.14;
double d = 3.14;
System.out.println(c == d); // true

2. 比较引用数据类型

对于对象(引用类型),== 比较的是对象在内存中的地址(即是否为同一个对象):

因为java是值传递,这里可能是地址的副本进行比较,根据这个副本也可以修改对象。

但是,这种比较不关心变量是否相同,只关心引用的对象是否相同。

String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2); // false,两个不同的对象,地址不同
String s3 = s1;
System.out.println(s1 == s3); // true,指向同一个对象

注意点

(1)基本类型 vs 包装类(==比较)

(2)包装类 vs 包装类(==比较)

二、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,内容相同
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
System.out.println(list1.equals(list2)); // true,两个空列表内容相同

3. 重写 equals () 的规范

重写 equals() 时需遵循以下规则(来自《Effective Java》):

4. 重写示例(自定义类)

public class User {
    private String id;
    private String name;
    // 构造方法、getter、setter 省略
    @Override
    public boolean equals(Object o) {
        // 1. 自身判断
        if (this == o) return true;
        // 2. 类型判断
        if (o == null || getClass() != o.getClass()) return false;
        // 3. 内容比较
        User user = (User) o;
        return Objects.equals(id, user.id) && 
               Objects.equals(name, user.name);
    }
}

注意点

三、hashCode () 方法

hashCode() 也是 Object 类的方法,返回一个 int 类型的哈希值,主要用于哈希表(如 HashMap、HashSet)中快速定位对象。

1. 基本作用

2. 默认实现

Object 类的 hashCode() 返回对象的内存地址转换后的整数(不同 JVM 实现可能不同)。

3. 重写原则

关键规则:如果两个对象通过 equals() 比较相等,则它们的 hashCode() 必须返回相同的值。反之则不成立(不同对象也可能有相同哈希值,即哈希冲突)。

这是因为哈希表在判断对象是否存在时,会先通过哈希值定位,再用 equals() 精确比较。若违反此规则,会导致哈希表无法正常工作:

// 反例:equals相等但hashCode不同
class BadExample {
    private int value;
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        BadExample that = (BadExample) o;
        return value == that.value;
    }
    @Override
    public int hashCode() {
        return (int) (Math.random() * 1000); // 错误实现:相同对象可能返回不同哈希值
    }
}

4. 正确的重写实现

通常结合对象中参与 equals() 比较的字段来计算哈希值:

@Override
public int hashCode() {
    // 使用 Objects.hash() 简化实现
    return Objects.hash(id, name);
}
// 等价于手动计算
@Override
public int hashCode() {
    int result = id != null ? id.hashCode() : 0;
    result = 31 * result + (name != null ? name.hashCode() : 0);
    return result;
}

使用 31 是因为它是一个质数,能减少哈希冲突,且 31 * i 可以被优化为 (i << 5) - i,提高计算效率。

四、三者之间的关系总结

  1. == 与 equals():

    • 未重写 equals() 时,两者功能一致(比较地址)
    • 重写 equals() 后,== 仍比较地址,equals() 比较内容
  2. equals() 与 hashCode():

    • 核心约定:equals() 为 true → hashCode() 必须相等
    • 反之不成立:hashCode() 相等 → equals() 不一定为 true(哈希冲突)
    • 实际应用:在哈希集合中,先通过 hashCode() 定位,再用 equals() 确认
  3. 使用场景:

    • 比较基本类型 → 用 ==
    • 比较对象地址 → 用 ==
    • 比较对象内容 → 用 equals()
    • 自定义类用于哈希表 → 必须同时重写 equals() 和 hashCode()

五、常见面试题解析

到此这篇关于一文读懂 Java 中的 ==、equals () 与 hashCode ()原理与避坑指南的文章就介绍到这了,更多相关java ==、equals () 与 hashCode ()内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文