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

时间:2015-04-07 18:45:06

标签: java equals hashcode

我作为密钥存储在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将“看到”我的两个对象的hashCodes不同,并得出结论没有必要调用equals()。如果这是真的,HashMap正在执行合同中的至少一部分。而且,这可能是HashMap优化的另一种表现形式。

但是,你(greenSocksRock)写道,“...你的密钥的hashCode()实现没有为不同的密钥返回足够不同的哈希值。”你能详细说明吗?

感谢。

PS对不起,我还在试图找出StackOverflow编辑器的方法。

3 个答案:

答案 0 :(得分:3)

编译器和JVM都没有强制执行hashCode / equals协定。 合同在Object您的班级之间,即您有责任遵守和执行该合同!

在Java中,Object类列出了.equals().hashCode()的契约,这是大多数基于哈希的标准库类所依赖的。现在,如果您实现自己的类,它会隐式扩展Object,因此您应该在自己的实现中强制执行常规合同,如果您希望您的类与依赖该合同的其他类一起正常工作。 / p>

提醒一下,来自Object documentation

  

如果两个对象根据equals(Object)方法相等,则对两个对象中的每一个调用hashCode方法必须产生相同的整数结果。

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

我不确定我是否理解你在上一个问题中尝试做什么,当你说你想要防止在地图上添加一个对象时#34;。如果你愿意的话,那就是 肯定能够用自定义equals实现的东西。在将新条目添加到地图之前,请根据您的具体情况查看Map.containsKey()Map.containsValue()

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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

通过相同的逻辑,对于HashMap内的对象,只有在hashCode()方法为两个对象返回相同的哈希值时才会调用equals()方法。

因此,在实现自定义类时,始终建议不仅要覆盖equals()方法,还要覆盖hashCode()方法。