在重写hashCode时需要注意的事项

5
public class Person {
    private String name, comment;
    private int age;

    public Person(String n, int a, String c) {
        name = n;
        age = a;
        comment = c;
    }

    public boolean equals(Object o) {
        if (!(o instanceof Person))
            return false;
        Person p = (Person) o;
        return age == p.age && name.equals(p.name);
    }
}

人类类(Person)中hashCode方法的恰当定义是什么?
A. 返回super.hashCode();
B. 返回name.hashCode() + age * 7;
C. 返回name.hashCode() + comment.hashCode() / 2;
D. 返回name.hashCode() + comment.hashCode() / 2 - age * 3;
答案是 B。
有人可以解释一下为什么 C 和 D 是错误的吗?

你可以使用这些哈希码方法中的任何一个(A可能不会产生良好的结果),但B是最简单的方法。 - Jonas Czech
1
@JonasCz C 和 D 是错误的,因为它们与 equals 方法不一致。 - fps
3个回答

8
对于 A、C 和 D,hashCode() 可能会为返回 true 的两个 Person 实例返回不同的结果。也就是说,相等的两个 Person 可能返回不同的哈希码。
这显然违反了 Object.hashCode() 的契约:

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

对于 C 和 D,如果两个 Person 年龄和姓名相同但评论不同,则 equals() 返回 true,而 hashCode() 会产生不同的值。
对于 A,由于 Person 隐式继承自 Object 类(即不继承任何显式超类),因此只有在调用同一实例上的 super.hashCode() 时才会相等。根据 Object.hashCode() 文档:
尽可能地,Object类定义的hashCode方法应该对于不同的对象返回不同的整数。(通常通过将对象的内部地址转换为整数来实现,但Java™编程语言不要求使用这种实现技术。)因此,如果您有两个不同的Person类实例,它们都具有相同的姓名、年龄和注释,equals()将返回true,而hashCode()将返回不同的值,从而违反了hashCode()的约定。在实践中,这意味着Person类不能成为任何Map的键。

1
好的解释! :) - Abhishek Singh

4

equals 方法指出当两个对象具有相同的名称和年龄时,它们是相等的。这里的注释不影响相等性。

equals 和 hashCode 的契约要求 2 个相等的对象具有相同的 hashCode。

C 和 D 可能会违反此规则,因为具有相同名称和年龄但不同注释的对象会导致不同的 hashCode。


2

从粗略的阅读来看,似乎 B 更好,因为 equal() 方法考虑了这两个变量(即姓名和年龄)。


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