Java中的equals()、==和hashCode()的用法区别

发布时间:2021-09-14 16:53:01 作者:chen
来源:亿速云 阅读:116
# Java中的equals()、==和hashCode()的用法区别

## 引言

在Java编程中,对象比较和哈希码处理是日常开发中的常见操作。`equals()`、`==`和`hashCode()`这三个概念看似简单,但实际使用中容易混淆。本文将深入剖析它们的区别、联系以及最佳实践,帮助开发者避免常见的陷阱。

---

## 一、`==`运算符:引用比较

### 1.1 基本概念
`==`是Java中最基础的比较运算符,但它的行为在**基本数据类型**和**引用类型**上有本质区别:

```java
int a = 5;
int b = 5;
System.out.println(a == b); // true(值比较)

String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2); // false(引用地址比较)

1.2 引用类型比较规则

1.3 使用场景


二、equals()方法:逻辑相等

2.1 方法定义

Object类中的原始实现:

public boolean equals(Object obj) {
    return (this == obj);
}

默认行为与==相同,但可被重写。

2.2 重写规范(Java规范要求)

  1. 自反性x.equals(x)必须为true
  2. 对称性x.equals(y)y.equals(x)结果相同
  3. 传递性:若x.equals(y)y.equals(z),则x.equals(z)
  4. 一致性:多次调用结果不变
  5. 非空性:x.equals(null)必须返回false

2.3 典型重写示例

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Person person = (Person) o;
    return age == person.age && Objects.equals(name, person.name);
}

2.4 注意事项


三、hashCode()方法:哈希契约

3.1 基本作用

3.2 通用约定

  1. 同一对象多次调用应返回相同值(除非对象修改)
  2. equals()相等的对象必须具有相同哈希码
  3. equals()不相等的对象不要求哈希码不同(但不同能提升哈希表性能)

3.3 重写示例

@Override
public int hashCode() {
    return Objects.hash(name, age);
}

3.4 违反契约的后果

Map<Person, String> map = new HashMap<>();
Person p1 = new Person("Alice", 25);
map.put(p1, "Developer");

Person p2 = new Person("Alice", 25);
map.get(p2); // 可能返回null(若未正确重写hashCode)

四、三者关系深度解析

4.1 对比表格

特性 == equals() hashCode()
比较维度 内存地址 逻辑相等 哈希值
是否可重写
性能 O(1) 通常O(n) 通常O(1)
使用场景 引用同一对象 业务逻辑相等 哈希集合操作

4.2 协作关系图示

graph LR
    A[==] -->|引用相等| B[equals返回true]
    B --> C[hashCode必须相同]
    D[equals返回false] -->|建议| E[hashCode不同]

4.3 特殊案例:BigDecimal

BigDecimal d1 = new BigDecimal("1.0");
BigDecimal d2 = new BigDecimal("1.00");
d1.equals(d2); // false(精度不同)
d1.hashCode() == d2.hashCode(); // false

五、实际开发中的陷阱与解决方案

5.1 常见错误

  1. 只重写equals()不重写hashCode()
    • 导致HashMap等集合无法正确工作
  2. 使用可变字段参与哈希计算
    • 对象存入集合后修改字段会导致内存泄漏
    // 反例:
    public int hashCode() {
       return this.id; // 若id可变
    }
    

5.2 最佳实践

  1. IDE自动生成(IntelliJ/Eclipse)
  2. 使用java.util.Objects工具类:
    
    @Override
    public int hashCode() {
       return Objects.hash(field1, field2);
    }
    
  3. 对于不可变对象,缓存哈希值:
    
    private int hash; // 默认为0
    @Override
    public int hashCode() {
       if (hash == 0) {
           hash = Objects.hash(name, age);
       }
       return hash;
    }
    

六、扩展知识

6.1 IdentityHashMap

6.2 Java 14+的record类型

record Point(int x, int y) {}
// 自动生成规范的equals/hashCode

6.3 hashCode冲突处理


结论

  1. ==用于实例身份比较
  2. equals()实现业务逻辑相等
  3. hashCode()必须与equals()保持契约
  4. 三者协同工作才能保证Java集合的正确性

掌握这些区别能有效避免诸如”HashMap找不到已存在的键”、”HashSet出现重复元素”等典型问题。建议在定义值对象时,始终同时重写equals()hashCode()方法。 “`

(注:实际字符数约1950,具体可能因格式略有浮动)

推荐阅读:
  1. JAVA企业级应用TOMCAT实战
  2. CENTOS6.5安装java8

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:canvas使用注意点有哪些

下一篇:电脑怎么实现Linux+Windows双系统启动

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》