我们如何决定集合的hashCode()方法的最佳实现(假设equals方法已被正确重写)?


当前回答

对于简单类,通常最容易基于equals()实现检查的类字段实现hashCode()。

public class Zam {
    private String foo;
    private String bar;
    private String somethingElse;

    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (obj == null) {
            return false;
        }

        if (getClass() != obj.getClass()) {
            return false;
        }

        Zam otherObj = (Zam)obj;

        if ((getFoo() == null && otherObj.getFoo() == null) || (getFoo() != null && getFoo().equals(otherObj.getFoo()))) {
            if ((getBar() == null && otherObj. getBar() == null) || (getBar() != null && getBar().equals(otherObj. getBar()))) {
                return true;
            }
        }

        return false;
    }

    public int hashCode() {
        return (getFoo() + getBar()).hashCode();
    }

    public String getFoo() {
        return foo;
    }

    public String getBar() {
        return bar;
    }
}

最重要的是保持hashCode()和equals()的一致性:如果equals()对于两个对象返回true,那么hashCode()应该返回相同的值。如果equals()返回false,那么hashCode()应该返回不同的值。

其他回答

如果你使用eclipse,你可以使用以下方法生成equals()和hashCode():

生成hashCode()和equals()。

使用此函数,您可以决定使用哪些字段进行相等和散列代码计算,Eclipse将生成相应的方法。

当组合哈希值时,我通常使用boost c++库中使用的组合方法,即:

seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);

这在确保平均分配方面做得相当好。有关这个公式如何工作的一些讨论,请参阅StackOverflow的帖子:boost::hash_combine中的魔术数字

在http://burtleburtle.net/bob/hash/doobs.html上有关于不同哈希函数的很好的讨论

我更喜欢使用实用工具方法从谷歌集合库从类对象,帮助我保持我的代码干净。equals和hashcode方法通常都是从IDE的模板中创建的,所以它们的可读性不太好。

这里有一个非常严重的bug。

Zam obj1 = new Zam("foo", "bar", "baz");
Zam obj2 = new Zam("fo", "obar", "baz");

同样的hashcode

你可能想要

public int hashCode() {
    return (getFoo().hashCode() + getBar().hashCode()).toString().hashCode();

(现在你能在Java中直接从int获取hashCode吗?我认为它做了一些自动铸造。如果是这种情况,跳过toString,它很难看。)

对于简单类,通常最容易基于equals()实现检查的类字段实现hashCode()。

public class Zam {
    private String foo;
    private String bar;
    private String somethingElse;

    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (obj == null) {
            return false;
        }

        if (getClass() != obj.getClass()) {
            return false;
        }

        Zam otherObj = (Zam)obj;

        if ((getFoo() == null && otherObj.getFoo() == null) || (getFoo() != null && getFoo().equals(otherObj.getFoo()))) {
            if ((getBar() == null && otherObj. getBar() == null) || (getBar() != null && getBar().equals(otherObj. getBar()))) {
                return true;
            }
        }

        return false;
    }

    public int hashCode() {
        return (getFoo() + getBar()).hashCode();
    }

    public String getFoo() {
        return foo;
    }

    public String getBar() {
        return bar;
    }
}

最重要的是保持hashCode()和equals()的一致性:如果equals()对于两个对象返回true,那么hashCode()应该返回相同的值。如果equals()返回false,那么hashCode()应该返回不同的值。