最近我通读了这篇文章

该文件旨在有效且正确地定义hashCode()equals(),但我无法理解为什么我们需要覆盖这两种方法.

我如何才能做出有效实施这些方法的决定呢?

推荐答案

约书亚·布洛赫说有效的Java

必须在每个重写equals()的类中重写hashCode().否则将导致违反标的物总合同.hashCode(),这将阻止类与所有基于哈希的集合(包括HashMap、HashSet和Hashtable)一起正常运行.

让我们通过一个例子来try 理解它,如果我们在不覆盖hashCode()的情况下覆盖equals(),并try 使用Map.

假设我们有这样一个类,如果两个MyClass的对象的importantField相等(其中hashCode()equals()是由Eclipse生成的),则它们是相等的

public class MyClass {
    private final String importantField;
    private final String anotherField;

    public MyClass(final String equalField, final String anotherField) {
        this.importantField = equalField;
        this.anotherField = anotherField;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((importantField == null) ? 0 : importantField.hashCode());
        return result;
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        final MyClass other = (MyClass) obj;
        if (importantField == null) {
            if (other.importantField != null)
                return false;
        } else if (!importantField.equals(other.importantField))
            return false;
        return true;
    }
}

想象一下你有这个

MyClass first = new MyClass("a","first");
MyClass second = new MyClass("a","second");

Override only 100

如果只覆盖了equals,那么当您首先调用myMap.put(first,someValue)时,它将散列到某个bucket,当您调用myMap.put(second,someOtherValue)时,它将散列到另一个bucket(因为它们有不同的hashCode).因此,虽然它们是相等的,因为它们不会散列到同一个桶中,但 map 无法实现这一点,它们都留在 map 中.


虽然如果我们覆盖hashCode(),就没有必要覆盖equals(),但让我们看看在这个特殊情况下会发生什么,我们知道MyClass的两个对象是相等的,如果它们的importantField相等,但我们不覆盖equals().

Override only 100

如果您只覆盖hashCode,那么当您调用myMap.put(first,someValue)时,它会首先计算hashCode并将其存储在给定的存储桶中.然后,当您调用myMap.put(second,someOtherValue)时,它应该按照Map Documentation将第一个替换为第二个,因为它们是相等的(根据业务需求).

但问题是equals没有被重新定义,所以当map散列second并在bucket中迭代时,如果有一个对象k,那么second.equals(k)是真的,那么它将找不到任何对象,因为second.equals(first)将是false.

希望是清楚的

Java相关问答推荐

Spring安全实现多个SQL表身份验证

我可以从Java模块中排除maven资源文件夹吗?

为什么我的画布没有显示在PFA应用程序中?

Jooq外键关系

在spring—data中自动发现native—sql查询期间遇到重复的SQL别名[id]

Character::Emoji不支持带数字的字符吗?

扩展到弹出窗口宽度的JavaFX文本字段

在springboot 3中,当我调用api endpoint时,会出现404

为什么我的在一个范围内寻找素数的程序不能像S所期望的那样工作

有效的公式或值列表必须少于或等于255个字符

在处理2个映射表时,没有更多的数据可从套接字读取

如何在Java springboot中从一个端点发送多个时间响应?

有没有办法在o(log(N))中以系统的方式将数组中的小块元素复制和移动到新增长的数组中的左侧?

具有最大共同前景像素的图像平移优化算法

Java.time.OffsetDateTime的SQL Server数据库列类型是什么?

将java.util.Date(01.01.0001)转换为java.time.LocalDate将返回29.12.0000

Java嵌套流查找任意值

具有多个分析模式的复杂分隔字符串的正则表达式

java构造函数中的冻结操作何时发生?

如何转换Vector<;对象>;转换为int?