3

在阅读 equals() 和 hashcode() 时,我开始知道如果两个对象相等,那么它们的哈希码必须相等,反之亦然。

但下面的例子并没有反映这一点。

class Employee{

  private String name;

  Employee(String name){
    this.name = name;
  }

  @Override
  public boolean equals(Object obj) {           
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Employee other = (Employee) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

}

现在,如果我创建两个 Employee 对象作为

Employee e1 = new Employee("hi");
Employee e2 = new Employee("hi");

如果我这样做,即使它们的哈希码不同e1.equals(e2),它也会返回truee1.hashcode() ,这从打印中可以看出,并且e2.hashcode().

有人可以解释一下吗?

4

4 回答 4

10

您需要覆盖hashcode方法并提供与 equals 合同的实现。

   @Override
    public int hashCode() {
        return name == null ? 0 : name.hashCode();
    }
  • 如果一个类覆盖equals,它必须覆盖hashCode
  • 当它们都被覆盖equals并且hashCode必须use the same set of fields
  • 如果两个对象是equal,那么它们的hashCode值也必须equal
  • 如果对象是immutable,则hashCode是缓存的候选对象,并且lazy initialization

您可以在此处阅读有关实现哈希码的信息

如果您不覆盖该方法,则将从Object类中使用默认行为。

在合理可行的情况下,由 Object 类定义的 hashCode 方法确实为不同的对象返回不同的整数。(这通常通过将对象的内部地址转换为整数来实现,但 JavaTM 编程语言不需要这种实现技术。)

基于哈希的[HashMap,HashSet,Hashtable,LinkedHashSet,WeakHashMap]集合将用于hashCode()在存储桶中查找/存储对象,然后它们将调用equals().

于 2012-10-13T18:11:42.930 回答
3

这是因为,每次您覆盖equals方法时,您也必须覆盖hashcode方法。

否则,您的对象将根据您的代码进行比较,但它们的 HashCode 将根据 Object 类中的预定义算法计算。

注意: - 通常,您在检查是否objects相等时考虑了所有参数,您应该使用它all those parameters来计算hashcodes每个object.

请参阅这篇非常好的帖子,其中描述了equalshashcode方法的使用。

引用这篇文章中的一句话,我已经在上面描述过:-

使用相同的字段集来计算hashcode您在equals方法中使用的字段

让我们看下面的 Demo 来理解上面的语句:-

public class Demo {
    private String str;
    private String name;

    public boolean equals(Object obj) {
        // Suppose you compare two objects based on length of their name variable

        // If name equals, object are equal
        if (obj instanceof Demo) {
            return this.name.equals(((Demo)obj).name);
        }
        return false;
    }

    // ****** Badly Overrided hashcode *******
    public int hashcode() {
        // But you calculate hashcode using both the fields

        // You should never use this kind of code in hashcodes. 
        // Use complex algorithm which gives you distinct result for 
        // objects that are not equal.
        return str.length + name.length;
    }
}

因此,如果两个对象具有相同的name,那么它们将相等,但如果它们的str字段具有不同length的 ,那么它们hashcodes将是不同的。

这就是为什么,您应该始终使用same fieldsinequalshashcode计算。

于 2012-10-13T18:11:40.823 回答
0

您应该覆盖哈希码方法。如果一个类覆盖了equals,那么当它们都被覆盖时它必须覆盖hashCode,如果两个对象相等,equals和hashCode必须使用相同的字段集,那么它们的hashCode值也必须相等,如果对象是不可变的,那么hashCode是缓存和延迟初始化的候选者

于 2012-10-13T19:06:13.407 回答
0

您还需要覆盖hashCode以获得您期望的行为。的默认实现Object.hashCode可能是返回对象引用,尽管根据文档这不是必需的。

如果没有覆盖hashCode,您就不能期望得到专门的结果;这类似于覆盖equals

于 2012-10-13T18:12:10.197 回答