最近我读了这篇文章 开发人员工作文件。

该文档是关于有效和正确地定义hashCode()和equals(),但我无法弄清楚为什么我们需要覆盖这两个方法。

我如何决定有效地实现这些方法?


当前回答

你必须重写hashCode()在每个 重写equals()的类。失败 这样做会导致违反 总合同 Object.hashCode(),它将防止 你的类不能正常运行 结合所有基于哈希的 集合,包括HashMap, HashSet和Hashtable。 摘自Joshua Bloch的《Effective Java》

通过一致地定义equals()和hashCode(),可以提高类作为基于散列的集合中的键的可用性。正如hashCode的API文档所解释的那样:“支持此方法是为了受益于诸如java.util.Hashtable所提供的哈希表。”

关于如何有效地实现这些方法的问题,最好的答案是建议你阅读《Effective Java》的第3章。

其他回答

你必须重写hashCode()在每个 重写equals()的类。失败 这样做会导致违反 总合同 Object.hashCode(),它将防止 你的类不能正常运行 结合所有基于哈希的 集合,包括HashMap, HashSet和Hashtable。 摘自Joshua Bloch的《Effective Java》

通过一致地定义equals()和hashCode(),可以提高类作为基于散列的集合中的键的可用性。正如hashCode的API文档所解释的那样:“支持此方法是为了受益于诸如java.util.Hashtable所提供的哈希表。”

关于如何有效地实现这些方法的问题,最好的答案是建议你阅读《Effective Java》的第3章。

它在使用值对象时很有用。以下摘自Portland Pattern Repository:

Examples of value objects are things like numbers, dates, monies and strings. Usually, they are small objects which are used quite widely. Their identity is based on their state rather than on their object identity. This way, you can have multiple copies of the same conceptual value object. So I can have multiple copies of an object that represents the date 16 Jan 1998. Any of these copies will be equal to each other. For a small object such as this, it is often easier to create new ones and move them around rather than rely on a single object to represent the date. A value object should always override .equals() in Java (or = in Smalltalk). (Remember to override .hashCode() as well.)

Java中的Equals和Hashcode方法

它们是java.lang. object类的方法,object类是所有类(自定义类以及java API中定义的其他类)的超类。

实现:

public boolean equals(对象obj) hashCode()

public boolean equals(对象obj)

这个方法只是检查两个对象引用x和y是否引用同一个对象。例如,它检查x是否== y。

它是自反的:对于任何参考值x, x = (x)应该返回true。

它是对称的:对于任何参考值x和y,当且仅当y = (x)返回true时,x = (y)应该返回true。

它是可传递的:对于任何参考值x、y和z,如果x = (y)返回true, y = (z)返回true,则x = (z)应该返回true。

它是一致的:对于任何参考值x和y, x.equals(y)的多次调用一致返回true或一致返回false,前提是对象上的等号比较中使用的信息没有被修改。

对于任何非空参考值x, x.equals(null)应该返回 假的。

hashCode()

此方法返回调用此方法的对象的哈希码值。此方法以整数形式返回哈希码值,支持基于哈希的集合类,如Hashtable、HashMap、HashSet等。必须在重写equals方法的每个类中重写此方法。

hashCode的一般契约是:

在Java应用程序的执行过程中,只要在同一个对象上多次调用hashCode方法,hashCode方法必须一致地返回相同的整数,前提是该对象上的等号比较中使用的信息没有被修改。

这个整数不需要在应用程序的一次执行和同一应用程序的另一次执行之间保持一致。

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

如果根据equals(java.lang.Object)方法,两个对象是不相等的,那么对每个对象调用hashCode方法必须产生不同的整数结果,这是不要求的。然而,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。

相等的对象必须产生相同的哈希代码,只要它们是 相等但不相等的对象不需要产生不同的哈希码。

资源:

JavaRanch

图片

简单地说,Object中的equals-方法检查引用是否相等,当属性相等时,类的两个实例在语义上仍然相等。例如,当将对象放入使用等号和hashcode(如HashMap和Set)的容器中时,这很重要。假设我们有这样一个类:

public class Foo {
    String id;
    String whatevs;

    Foo(String id, String whatevs) {
        this.id = id;
        this.whatevs = whatevs;
    }
}

我们创建了两个具有相同id的实例:

Foo a = new Foo("id", "something");
Foo b = new Foo("id", "something else");

如果不重写等号,我们将得到:

A.equals (b)为假,因为它们是两个不同的实例 a.equals(a)为真,因为它是同一个实例 b.equals(b)为真,因为它是同一个实例

正确吗?也许吧,如果这是你想要的。但假设我们希望具有相同id的对象是相同的对象,不管它是否是两个不同的实例。我们重写等号(和hashcode):

public class Foo {
    String id;
    String whatevs;

    Foo(String id, String whatevs) {
        this.id = id;
        this.whatevs = whatevs;
    }

    @Override
    public boolean equals(Object other) {
        if (other instanceof Foo) {
            return ((Foo)other).id.equals(this.id);   
        }
    }

    @Override
    public int hashCode() {
        return this.id.hashCode();
    }
}

至于实现equals和hashcode,我建议使用Guava的helper方法

我正在研究解释“如果你只覆盖hashCode,那么当你调用myMap.put(first,someValue)时,它首先接受,计算它的hashCode并将其存储在给定的桶中。然后,当你调用myMap.put(first,someOtherValue)时,它应该根据Map文档将first替换为second,因为它们是相等的(根据我们的定义)。”:

我认为第二次添加myMap时应该是第二个对象比如myMap。put(second,someOtherValue)