【发布时间】:2017-03-16 11:32:29
【问题描述】:
如果两个对象返回相同的hashCode,是不是意味着它们相等?或者我们需要equals来防止碰撞?
我可以通过比较 hashCodes 来实现 equals 吗?
【问题讨论】:
如果两个对象返回相同的hashCode,是不是意味着它们相等?或者我们需要equals来防止碰撞?
我可以通过比较 hashCodes 来实现 equals 吗?
【问题讨论】:
如果有 hashCode(),为什么 Java 还需要 equals()?
Java 需要equals(),因为它是通过检查类、字段和设计人员认为是相等性测试的一部分的其他条件来测试对象相等性的方法。
hashCode() 的目的是提供一个主要供散列表使用的散列值;虽然它也可以用于其他目的。返回的值基于对象的字段和其复合和/或聚合对象的哈希码。该方法不考虑对象的类或类型。
equals() 和 hashCode() 之间的关系是一种暗示。
后者不成立有几个原因:
hashCode() 可以是特定于实现的,在不同的 JVM 或 JVM 目标安装上返回不同的值。在同一个 JVM 中,hashCode() 可以用作相等的廉价前体,方法是首先测试已知的哈希码,并且只有在相同的测试实际相等的情况下;前提是相等性测试比生成哈希码要昂贵得多。
我可以通过比较 hashCodes 来实现 equals 吗?
没有。如前所述,相等的哈希码并不意味着相等的对象。
【讨论】:
如果两个对象具有相同的 hashCode,则它们不一定相等。否则你会发现完美的散列函数。但反之亦然——如果对象相等,那么它们必须具有相同的 hashCode。
【讨论】:
"FB".hashCode() == "Ea".hashCode().
hashCode 和 Equals 是关于对象的不同信息
考虑类比人,其中哈希码是生日,
在那种情况下,你和许多其他人有相同的生日(相同的哈希码),但是你们不是同一个人..
【讨论】:
有时(很多时候?)你不知道!
这些答案并非不真实。但他们并没有讲述整个故事。
一个示例是,您正在创建一组 SomeClass 类的对象,并且通过在构造函数中增加静态变量 nInstanceCount 或类似变量,为创建的每个实例分配一个唯一 ID:
iD = nInstanceCount++;
你的哈希函数可能然后是
int hashCode(){
return iD;
}
然后你的等号可能是
boolean equals( Object obj ){
if( ! ( obj instanceof SomeClass )){
return false;
}
return hashCode() == obj.hashCode();
}
...在这种情况下,您认为“等于是多余的”的想法实际上是正确的:如果所有类的行为都是这样,Java 10(或 Java 23)可能会说,啊,让我们摆脱愚蠢的老 equals , 重点是什么? (NB 向后兼容性将会消失)。
有两个要点:
然后您不能创建多个 MAXINT 的 SomeClass 实例。或者...您可以 ...如果您设置了一个系统来重新分配以前销毁的实例的 ID。 ID 通常是long 而不是int ...但这不起作用,因为hashCode() 返回int。
这些对象中的任何一个都不能与另一个对象“相等”,因为您已经定义了这个特定类的 equality = identity。这通常是可取的。通常它会关闭所有可能的途径......
您的问题的必要含义也许是,这两种方法有什么用,以一种相当烦人的方式,必须“合作”? Frelling 在他/她的回答中提到了关键点:需要散列码来分类到像 HashMap 这样的类的“桶”中。值得一读:为HashMap 之类的类设计高效的“桶”机制所涉及的高级数学数量非常可怕。读完之后,您可能会(和我一样)对如何以及为什么要费心实施hashCode() 稍加思考,产生一点理解和敬意!
【讨论】:
Oracle 文档中所述的hashCode 方法是Java 中对象的数字表示。此哈希码的可能值有限(由可以存储在 int 中的值表示)。
对于更复杂的类,您很有可能会找到两个具有相同哈希码值的不同对象。此外,没有人阻止您在任何课程中这样做。
class Test {
@Override
public int hashCode() {
return 0;
}
}
所以,不建议通过比较哈希码来实现equals方法。仅当您可以保证每个对象都有唯一的哈希码时,才应使用它们进行比较。在大多数情况下,您唯一可以确定的是,如果两个对象使用 o1.equals(o2) 相等,则 o1.hashCode() == o2.hashCode()。
在equals 方法中,您可以定义更复杂的逻辑来比较同一类的两个对象。
【讨论】:
如果两个对象返回相同的hashCode,是不是等于它们相等?
不,不是那个意思。
Object 的 javadocs 声明如下:
hashCode的总合约是:
- 在 Java 应用程序执行期间,在同一对象上多次调用时,
hashCode方法必须始终如一 返回相同的整数,但未提供equals中使用的信息 对象上的比较被修改。 ...- 如果两个对象根据
equals(Object)方法相等,那么必须对这两个对象中的每一个调用hashCode方法 产生相同的整数结果。- 如果两个对象根据
equals(java.lang.Object)方法不相等,则不要求调用hashCode方法 这两个对象中的每一个都必须产生不同的整数结果。 ...
注意突出显示的语句。它清楚地对您的问题说“不”。
还有另一种看法。
hashCode 返回一个int。int 只能采用 232 个不同的值。a.hashCode() == b.hashCode() 隐含 a.equals(b),那么在运行的 Java 应用程序中的任何给定时间都只能有 232 个不同(即互不相等)的对象。最后一点显然不正确。事实上,如果您有足够大的堆来在 64 位 JVM 中容纳 232 个 java.lang.Object ... 的实例,这显然是不正确的。
第三种方法是一些众所周知的例子,其中两个不同的两个字符串具有相同的哈希码。
鉴于您的假设不正确,由此得出的推理也是不正确的。
equals 方法。hashCode 来实现 equals。您可以使用hashCode 实现更快的equals 方法,但前提是调用hashCode 两次比比较两个对象更快。一般不会。
【讨论】:
hashCodes 相等 -> 对象可能相等 -> 需要进一步比较
hashCodes 不同 -> 对象不相等(如果 hashCode 实现正确)
这就是equals方法的实现方式。首先,您检查 hashCodes 是否相等。如果是,您需要检查类字段以查看它是否代表完全相同的对象。如果 hashCode 不同,可以确定对象不相等。
【讨论】: