两个具有相同哈希码的Java对象是否一定相等?

23

我了解为什么对于两个相等(通过equals)的对象提供相同的哈希码很重要。但是反过来是否也成立,如果两个对象具有相同的哈希码,它们必须相等吗?这个契约仍然有效吗?我找不到一个可能发生这种情况的例子,因为如果所有参与equals方法的属性也被用于覆盖hashcode方法,那么我们将始终使用相同的哈希码来比较相等的对象。请评论。


2
请参见https://dev59.com/v2855IYBdhLWcg3waDeR。 - esaj
10个回答

66
如果两个对象具有相同的hashcode,它们未必相等。换言之,你将会发现完美的哈希函数是不存在的。
但相反的情况成立:如果这些对象相等,则它们必须具有相同的hashcode

8
+1 这也适用于哈希对象的通用情况,不仅限于Java对象。 - MByD
考虑这个示例。在这里,firstBooksecondBook具有不同的哈希码。那么你的语句如何成立,即“如果对象相等,则它们具有相同的哈希码”? - Fresher
@Fresher - 对于回复晚了感到抱歉。当两个对象相等时,你必须重写 hashcode 方法,以保证它们的哈希码也相等。否则,在使用对象进行集合操作时可能会出现问题。在你给出的例子中,他们写道如果你重写了 equals() 方法,那么必须同时重写 hashCode() 方法。你只看到了段落中关于 equals 方法的声明,因为他们只是在讨论该方法。请注意上方有 ...,这表示故意没有写出 hashcode 方法,只展示了 equals 方法。但是,你必须添加 hashcode 方法。 - Petar Minchev
你能举个例子说明“如果两个对象具有相同的哈希码,则它们不一定相等”的情况吗?考虑到“如果这些对象相等,则它们必须具有相同的哈希码”,我发现这很难理解。如果两个对象具有相同的哈希码,它们怎么可能不是相同的呢?因为只有当两个对象相同时才会生成相同的哈希码。 - NoName
Java中的哈希码只是将对象映射到整数的函数。根据哈希码函数的实现,两个不同的对象可能会产生相同的哈希码,这被称为冲突。您希望最小化冲突的数量,但实现完美的哈希函数(即不产生冲突的函数)并不总是容易且可行的,因为哈希码是int类型,而int类型仅有2^32个可能的值。假设您想计算字符串的哈希码。可能的字符串数量远大于int类型的2^32个可能值。 - Petar Minchev
显示剩余4条评论

10
hashCode 函数的目的是允许对象快速分成一组已知不等于其它所有项的集合。假设有1000个项,并将它们分成大约相等的十个集合。调用 hashCode 可以快速识别该项与900个项不相等,而无需对这些项中的任何一个使用 equals。即使必须使用 equals 将该项与100个其他项进行比较,这仍然只有与所有1000个项进行比较的1/10 的成本。实际上,即使在大型集合中,hashCode 通常也会消除99.9% 或更多的不相等项,最多只剩下少数需要检查。

7
根据Javadoc文档:http://download.oracle.com/javase/6/docs/api/java/lang/Object.html#hashCode%28%29 虽然equals(java.lang.Object)方法判断两个对象不相等,但调用这两个对象的hashCode方法返回的整数结果并不一定不同。程序员应该知道,为不相等的对象产生不同的整数结果可能会提高哈希表的性能。
注:在实际情况中,两个字符串可能具有相同的哈希码。例如,如果您想存储包含小写英文字母(如“aaaaaaaaaa”,“aaaaaaaaab”等)的所有长度为10的字符串组合,则无法为每个141.167.095.653.376个组合分配唯一的哈希码,因为Java中的int是32位,因此最多可以有4.294.967.296个不同的值。

5

hashCode 的值取决于实现方式。例如,String 类实现了 hashCode() 函数并依据其值进行计算。这意味着

String a=new String("b");
String b=new String("b");

两个对象的hashcode可能相同,但它们是不同的对象。因此,a==b会返回false


3
事实上
public int hashCode(){
    return 1;
}

这是一个有效的哈希码实现...但是非常糟糕。会使所有的哈希表变慢。 但是,是的,你可以有两个不同的对象具有相同的哈希码。但这不应该是普遍情况,一个真正的实现应该大部分时间给出不同值的哈希码。


这是一个有效的论点。哈希码必须满足的唯一属性以确保正确性的是:仅当基础数据结构不同才应该有不同的哈希码。这是因为不同的哈希码,根据设计,意味着不同的底层结构。 - Jasim
“不同的底层结构”是什么意思? - NoName

3

有趣的是,NumberFormat是Java基础类的一个例子,它违反了以下推荐:

只要合理可行,由Object类定义的hashCode方法应为不同对象返回不同整数。

这里是一些代码展示,至少在我当前运行的Mac OS X 10.6版本的Java下如此。

Numberformat nf = NumberFormat.getNumberInstance();
NumberFormat nf2 = NumberFormat.getNumberInstance();
assert nf != nf2;  // passes -- they are different objects
assert !nf.equals(nf2);  // passes -- they are not equal
assert nf.hashCode() != nf2.hashCode();  // fails -- same hash code

0

为了证明,如果两个对象具有相同的hashCode并不意味着它们相等

假设您有两个用户定义的类

    class Object1{
        private final int hashCode = 21;
        public int hashCode(){
            return hashCode;
        }

        public boolean equals(Object obj) {
            return (this == obj);
        }
    }

    class Object2{
        private final int hashCode = 21;
        public int hashCode(){
            return hashCode;
        }

        public boolean equals(Object obj) {
            return (this == obj);
        }
    }

    Object1 object1 = new Object1();
    Object2 object2 = new Object2(); 

    Object1 object3 = new Object1();


    if(object1.hashCode() == object2.hashCode()){
         // return true, because the hashcodes are same
    }

    but 
    if(object1.equals(object3)){
            // will fail, because two different objects   
    }

0

hashcode() 方法为每个对象返回一个唯一的整数 ID。如果一个对象的 hashcode 不同于另一个对象的 hashcode,则无需执行 equals() 方法:您只需要知道这两个对象不相同即可。另一方面,如果 hashcode 相同,则必须执行 equals() 方法以确定值和字段是否相同。


0

0

哈希码方法返回整数。如果整数范围结束,那么两个不同的对象也将具有相同的哈希码。因此,并不一定两个不同的对象具有相同的哈希码就相等。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接