如何确保hashCode()与equals()一致?

2022-09-01 22:36:33

当覆盖java.lang.Object的equals()函数时,javadocs建议,

每当重写hashCode方法时,通常需要重写该方法,以便维护hashCode方法的一般契约,该合约规定相等的对象必须具有相等的哈希代码。

hashCode() 方法必须为每个对象返回一个唯一的整数(这在基于内存位置比较对象时很容易做到,只需返回对象的唯一整数地址)

应该如何重写hashCode()方法,以便它仅基于该对象的属性为每个对象返回唯一的整数


public class People{
   public String name;
   public int age;

   public int hashCode(){
      // How to get a unique integer based on name and age?
   }
}
/*******************************/
public class App{
   public static void main( String args[] ){
       People mike = new People();
       People melissa = new People();
       mike.name = "mike";
       mike.age = 23;
       melissa.name = "melissa";
       melissa.age = 24;
       System.out.println( mike.hasCode() );  // output?
       System.out.println( melissa.hashCode(); // output?
   }
}

答案 1

它并没有说一个对象的哈希码必须是完全唯一的,只是两个相等对象的哈希码返回相同的哈希码。让两个不相等的对象返回相同的哈希码是完全合法的。但是,哈希码分布在一组对象上越独特,HashMaps和其他使用哈希码的操作的性能就越好。

像IntelliJ Idea这样的IDE具有用于equals和hashCode的内置生成器,它们通常可以很好地为大多数对象提供“足够好”的代码(并且可能比一些手工制作的过于聪明的哈希函数更好)。

例如,下面是 Idea 为 People 类生成的哈希代码函数:

public int hashCode() {
    int result = name != null ? name.hashCode() : 0;
    result = 31 * result + age;
    return result;
}

答案 2

我不会详细介绍hashCode唯一性的细节,因为Marc已经解决了这个问题。对于你的班级,你首先需要决定一个人的平等意味着什么。也许平等仅仅基于他们的名字,也许它基于名字和年龄。它将是特定于域的。假设平等是基于名字和年龄的。您被覆盖的看起来像Peopleequals

public boolean equals(Object obj) {
    if (this==obj) return true;
    if (obj==null) return false;
    if (!(getClass().equals(obj.getClass())) return false;
    Person other = (Person)obj;
    return (name==null ? other.name==null : name.equals(other.name)) &&
        age==other.age;
}

任何时候覆盖 都必须覆盖 。此外,在计算中不能使用比实际更多的字段。大多数时候,您必须添加或排除各种字段的哈希代码(哈希代码应该快速计算)。因此,有效的方法可能如下所示:equalshashCodehashCodeequalshashCode

public int hashCode() {
    return (name==null ? 17 : name.hashCode()) ^ age;
}

请注意,以下内容无效,因为它使用的字段不是(高度)。在这种情况下,两个“等于”对象可能具有不同的哈希代码。equals

public int hashCode() {
    return (name==null ? 17 : name.hashCode()) ^ age ^ height;
}

此外,对于两个不相等的对象具有相同的哈希代码是完全有效的:

public int hashCode() {    
    return age;    
}

在这种情况下,Jane 30岁不等于Bob 30岁,但他们的哈希代码都是30岁。虽然有效,但这对于基于哈希的集合的性能来说是不希望的。