编译器或 JVM 是否强制执行 hashCode/equals 契约?

Does the compiler, or JVM, enforce the hashCode/equals contract?

我存储在 HashMap 中的对象作为键覆盖 equals() 但不是 hashCode();当我将对象放入地图时,没有调用 equals() 方法。如果我还覆盖 hashCode(),则调用 equals() 方法。这是为什么?

为什么我无法使用自定义 equals 方法来阻止将对象添加到地图,无论我是否重写 hashCode()?

谢谢。

package package1;

public class PlayWithHash {

    public static void main(String [] args){
        java.util.Map<Cat, Cat> map = new java.util.HashMap<Cat, Cat>();
        map.put(new Cat(), new Cat());
        map.put(new Cat(), new Cat());
        System.out.println("hashmap size = " + map.size());
    }
}

class Cat{
    @Override
    public int hashCode(){
        return 1;
    }
    @Override
    public boolean equals(Object d){
        Cat c = (Cat) d;
        if(this.hashCode() == c.hashCode()){
            return true;
        }
        return false;
    }
}

如果hashCode()被注释,size = 2,否则size = 1。

我在想,如果我不覆盖 hashCode() 而是使用 Object 的 hashCode(),HashMap 将“看到”我的两个对象的 hashCode 不同,并得出结论没有需要调用 equals()。如果这是真的,那么 HashMap 正在执行,至少是部分合同。并且,这可能是HashMap优化的另一种体现。

但是,您 (greenSocksRock) 写道,“……您的密钥的 hashCode() 实现没有为不同的密钥返回足够不同的哈希值。”请详细说明一下好吗?

谢谢。

PS 抱歉,我仍在尝试使用 Whosebug 的编辑器。

据我所知编译器不强制执行它。 阅读本文以更好地理解该主题 http://tutorials.jenkov.com/java-collections/hashcode-equals.html

编译器和 JVM 都不强制执行 hashCode/equals 契约。 该合同是在 Object 您的 class 之间签订的,即您有责任遵守并执行该合同!

在 Java 中,Object class 列出了 .equals().hashCode() 的契约,其中大多数基于散列的标准库 classes 依赖。现在,如果您实现自己的 class,它会隐式扩展 Object,因此,如果您希望 class 与其他实现正常工作,则您应该在自己的实现中执行通用契约class依赖该合同的 es。

提醒一下,来自 Object documentation:

If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

在没有看到你的实现的情况下,我只能猜测当你将对象放入 Map 时为什么会调用 equals(),我的猜测是 hashCode()您的密钥的实现没有为不同的密钥返回足够不同的哈希值。
例如,当您将某些内容放入 HashMap 时,它会调用键的 hashCode() 方法,以找到一个位置来存储您的值。如果该位置已经包含一个值,则可能会调用键的 equals() 方法来确定下一步该做什么。

当你说你想 "prevent the addition of an object to a map" 时,我不确定我是否理解你在上一个问题中试图做的事情。如果您愿意,您 绝对可以使用自定义 equals 实现来做到这一点。在将新条目放入地图之前,根据您的情况查看 Map.containsKey()Map.containsValue()

最后,如果可以的话,我建议您查看 Joshua Bloch 的 "Effective Java, 2nd ed." 中的第 8 项和第 9 项以获得更深入的解释。

哈希图在内部实现为链表的集合。搜索对象(使用传递的键)的通常机制是首先对键进行散列,然后遍历与散列值对应的链表中的各个对象。

根据相同的逻辑,对于 HashMap 中的对象,只有在 hashCode() 方法 returns 两个对象的哈希值相同时才会调用 equals() 方法。

因此,在实现自定义 类.

时,始终建议不仅要覆盖 equals() 方法,还要覆盖 hashCode() 方法