写两个hascode和equals的例子

目录

[示例1:不重写 hashCode 和 equals](#示例1:不重写 hashCode 和 equals)

[示例2:只重写 equals 方法](#示例2:只重写 equals 方法)

[示例3:正确重写 equals 和 hashCode](#示例3:正确重写 equals 和 hashCode)

示例4:在哈希集合中的行为

关键规则总结:


我将通过几个例子来帮助你理解 hashCodeequals 方法的作用和使用场景。

示例1:不重写 hashCodeequals

复制代码
public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public static void main(String[] args) {
        Person p1 = new Person("Alice", 25);
        Person p2 = new Person("Alice", 25);

        System.out.println(p1.equals(p2)); // false
        System.out.println(p1.hashCode() == p2.hashCode()); // false
    }
}

解释

  • 默认的 equals 方法比较的是对象的引用(是否为同一个对象)
  • 默认的 hashCode 返回对象的内存地址转换后的整数
  • 即使两个对象内容相同,它们也是不同的对象实例

示例2:只重写 equals 方法

复制代码
public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 重写equals方法
    @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 && name.equals(person.name);
    }

    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
        System.out.println(p1.hashCode() == p2.hashCode()); // false
    }
}

解释

  • 重写后 equals 根据内容判断为 true
  • hashCode 仍基于内存地址,导致哈希值不同
  • 问题 :这违反了 hashCode 的约定(相等的对象必须有相同的哈希值)

示例3:正确重写 equalshashCode

复制代码
import java.util.Objects;

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 重写equals方法
    @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 && name.equals(person.name);
    }

    // 重写hashCode方法
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    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
        System.out.println(p1.hashCode() == p2.hashCode()); // true
    }
}

解释

  • equals 根据内容判断对象是否相等
  • hashCode 根据内容计算哈希值
  • 符合 Java 规范:相等的对象必须有相同的哈希值

示例4:在哈希集合中的行为

复制代码
import java.util.HashSet;
import java.util.Set;

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @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 && name.equals(person.name);
    }

    @Override
    public int hashCode() {
        return name.hashCode() + age;
    }

    public static void main(String[] args) {
        Set<Person> set = new HashSet<>();
        set.add(new Person("Bob", 30));
        set.add(new Person("Bob", 30));

        System.out.println(set.size()); // 1
    }
}

解释

  • 由于正确重写了 equalshashCode
  • HashSet 能够正确判断两个内容相同的对象为重复元素
  • 如果没有正确重写这两个方法,Set 会包含重复元素

关键规则总结:

  1. equals 的约定
    • 自反性:x.equals(x) 必须为 true
    • 对称性:x.equals(y) 为 true 时,y.equals(x) 也必须为 true
    • 传递性:如果 x.equals(y) 和 y.equals(z) 为 true,则 x.equals(z) 也必须为 true
    • 一致性:多次调用 x.equals(y) 结果不变
    • 任何非 null 对象与 null 比较结果为 false
  1. hashCode 的约定
    • 相等的对象必须具有相同的哈希值
    • 哈希值在对象的生命周期内不应改变
    • 不相等的对象可以有相同的哈希值(哈希冲突)
  1. 最佳实践
    • 当重写 equals 方法时,必须重写 hashCode 方法
    • 使用相同的字段来计算 equalshashCode
    • 可以使用 Objects.hash() 方法简化 hashCode 的实现
相关推荐
测试员周周3 小时前
【Appium 系列】第16节-WebView-H5上下文切换 — 混合应用的自动化难点
运维·开发语言·人工智能·功能测试·appium·自动化·测试用例
Mahir085 小时前
Spring 循环依赖深度解密:从问题本质到三级缓存源码级解析
java·后端·spring·缓存·面试·循环依赖·三级缓存
杜子不疼.5 小时前
【C++ AI 大模型接入 SDK】 - DeepSeek 模型接入(上)
开发语言·c++·chatgpt
加号35 小时前
【C#】 串口通信技术深度解析及实现
开发语言·c#
sycmancia6 小时前
Qt——编辑交互功能的实现
开发语言·qt
RyFit6 小时前
SpringAI 常见问题及解决方案大全
java·ai
石山代码6 小时前
C++ 内存分区 堆区
java·开发语言·c++
心中有国也有家6 小时前
cann-recipes-infer:昇腾 NPU 推理的“菜谱集合”
经验分享·笔记·学习·算法
绝知此事7 小时前
【算法突围 01】线性结构与哈希表:后端开发的收纳术
java·数据结构·算法·面试·jdk·散列表
无风听海7 小时前
C# 隐式转换深度解析
java·开发语言·c#