一句话说透Java里面的equal、hash、==

181 阅读2分钟

一句话总结:
== 比地址,equals 比内容,hashCode 是身份证号——三个兄弟各司其职,协作才能不乱套!


一、== 运算符:认脸不认人

  • 作用:比较两个变量的内存地址是否相同(是不是同一个对象)。

  • 适用场景

    • 基本数据类型(intdouble 等):直接比
    • 对象类型(String自定义类):比地址(是否指向同一块内存)。
int a = 10;  
int b = 10;  
System.out.println(a == b); // true(值相等)  

String s1 = new String("喵");  
String s2 = new String("喵");  
System.out.println(s1 == s2); // false(不同对象,地址不同)  

二、equals() 方法:认内容不认脸

  • 默认行为:和 == 一样,比地址(Object 类的默认实现)。
  • 重写后:比对象内容是否相同(如 StringInteger 等已重写)。
  • 重点自定义类必须手动重写 equals() 才能比内容!
class Cat {  
    String name;  
    Cat(String name) { this.name = name; }  

    // 手动重写 equals()  
    @Override  
    public boolean equals(Object obj) {  
        if (this == obj) return true; // 地址相同直接返回 true  
        if (obj == null || getClass() != obj.getClass()) return false;  
        Cat cat = (Cat) obj;  
        return Objects.equals(name, cat.name); // 比名字内容  
    }  
}  

Cat c1 = new Cat("咪咪");  
Cat c2 = new Cat("咪咪");  
System.out.println(c1.equals(c2)); // true(内容相同)  
System.out.println(c1 == c2);       // false(地址不同)  

三、hashCode() 方法:身份证号

  • 作用:返回对象的哈希码(整数),用于哈希表(如 HashMapHashSet)快速查找。

  • 核心规则

    1. 如果两个对象 equals() 为 true,它们的 hashCode() 必须相同(否则哈希表会错乱)。
    2. hashCode() 相同,equals() 不一定为 true(哈希碰撞正常)。
// 错误示例:重写 equals() 但没重写 hashCode()  
class Dog {  
    String name;  
    @Override  
    public boolean equals(Object obj) { /* 比名字 */ }  
    // 没重写 hashCode() → 默认用 Object 的 hashCode()(不同对象值不同)  
}  

Dog d1 = new Dog("旺财");  
Dog d2 = new Dog("旺财");  
Set<Dog> set = new HashSet<>();  
set.add(d1);  
set.add(d2);  
System.out.println(set.size()); // 输出 2!因为 hashCode 不同  

正确做法

@Override  
public int hashCode() {  
    return Objects.hash(name); // 用 name 生成哈希码  
}  
// 此时 d1 和 d2 的 hashCode 相同,set.size() 为 1  

四、三者关系总结

操作比较内容重写要求常见用途
==内存地址不能重写基本类型比较、对象地址判断
equals()对象内容需手动重写自定义对象内容比较
hashCode()哈希码(整数)必须和 equals() 一致哈希表存储与查找

五、避坑指南

  1. 永远同时重写 equals() 和 hashCode()

    • 用 IDE 自动生成(如 IntelliJ 的 Generate → equals() and hashCode())。
    • 或用 Objects.equals() 和 Objects.hash() 简化代码。
  2. 处理 null 安全

    @Override  
    public boolean equals(Object obj) {  
        if (this == obj) return true;  
        if (obj == null || getClass() != obj.getClass()) return false;  
        // ...  
    }  
    
  3. 小心可变字段参与哈希计算

    • 如果对象字段会变,可能导致存进哈希表后找不到(哈希码变了,但存储位置没变)。

总结口诀:

“基本类型用 ==,对象地址也比它。
内容相等用 equals,重写别忘 hashCode。
哈希一致是铁律,否则 Map 要崩盘!”