Java 使用具有两个泛型字段的类重写哈希代码

Java 使用具有两个泛型字段的类重写哈希代码,java,hashmap,hashcode,keyvaluepair,Java,Hashmap,Hashcode,Keyvaluepair,我正在实现一个类对,将其用作一个具有两个值的键,用于HashMap。我使用泛型来保持字段变量的类型。我成功地编写了代码的最大部分: public class Pair<L, R> { private L left; private R right; Pair(L left, R right) { this.left = left; this.right = right; } public L ge

我正在实现一个类
,将其用作一个具有两个值的键,用于
HashMap
。我使用泛型来保持字段变量的类型。我成功地编写了代码的最大部分:

public class Pair<L, R>
{
    private L left;
    private R right;


    Pair(L left, R right)
    {
        this.left = left;
        this.right = right;
    }


    public L getLeft()
    {
        return left;
    }


    public R getRight()
    {
        return right;
    }


    public void setLeft(L left)
    {
        this.left = left;
    }


    public void setRight(R right)
    {
        this.right = right;
    }


    @Override
    public boolean equals(Object obj)
    {
        if (obj instanceof Pair< ? , ? >)
        {
            Pair< ? , ? > pair = (Pair< ? , ? >)obj;
            return left.equals(pair.getLeft()) && right.equals(pair.getRight());
        }
        return false;
    }

    @Override
    public String toString()
    {
        return "Pair " + Integer.toHexString(hashCode()) + ": (" + left.toString() + ", " + right.toString()
               + ")";
    }
}
公共类对
{
列兵L左;
私权;
成对(左左,右)
{
this.left=左;
这个。右=右;
}
公共L getLeft()
{
左转;
}
公共权利
{
返还权;
}
公共无效设置左(左)
{
this.left=左;
}
公共无效设定权(右)
{
这个。右=右;
}
@凌驾
公共布尔等于(对象obj)
{
if(对的obj实例<?,?>)
{
配对<?,?>配对=(配对<?,?>)obj;
返回left.equals(pair.getLeft())和&right.equals(pair.getRight());
}
返回false;
}
@凌驾
公共字符串toString()
{
返回“Pair”+Integer.toHexString(hashCode())+”:(“+left.toString()+”,“+right.toString())
+ ")";
}
}
我的问题是创建适当的
hashCode
方法,它为相同的对象提供相同的hashCode,为不同的对象提供不同的hashCode。一些提示?

这应该可以做到(当然,哈希代码永远不能保证是不同的)


如果left或right可以为null,您需要更多的代码来处理它。

不要重新发明轮子


只需使用

您已经在依赖左
和右
equals
方法,那么为什么不也依赖它们的
hashcode

@Override
public int hashCode()
{
    final int prime = 31;
    int result = 1;
    result = prime * result + (left ==null? 0 : left.hashCode());
    result = prime * result + (right ==null? 0 : right.hashCode());
    return result;
}

相等的对象应该有相同的散列码,但两个不相等的对象不一定有不同的散列码(tho,它们应该经常不同)。这是使用just
return objects.hash(左、右)时免费获得的至少Oracle的Java 7实现正好使用了这一点。但是,使用JRE方法允许将来的改进…@Holger是的,感谢您指出,我不知道该方法(仍在JDK 6上),但是,它看起来像
对象。hash()
会导致额外的数组创建,这在本例中可能无关紧要,但值得考虑。好建议,我也想过使用左右哈希代码,但不知道如何以最佳方式使用它们。无论如何,我最好还是坚持使用本机java实现。这正是我一直在寻找的!它对Java1.7真的很有帮助。但是,您可能会注意到,对于Java1.6及更低版本,我们应该选择什么?@Puzzle:复制即可。它非常简单,可以与1.6甚至1.5一起使用…@Holger:是什么让你认为
left.hashCode()-right.hashCode()
提供了更好的结果?不难想象,
left.hashCode()-right.hashCode()
是个坏主意。。。例如,
Integer
类将值作为hashCode返回;因此,如果您使用这个泛型类来创建整数对,那么创建哈希冲突就非常容易(在正常使用情况下也很有可能)。hashCode
针对任意
字符串进行了优化,最好是人类可读的文本。它没有针对
字符串
进行优化,在65536个可能的字符中最多使用12个不同的字符。仅仅因为很难看到缺陷并不意味着这是一个更好的解决方案。您的解决方案只是隐藏正在发生的事情。我不认为String.hashCode对字符串的内容做出任何假设。请看,做出任何假设的不是方法
String.hashCode
,而是用来证明结果足够的一组测试用例,这会产生不同。“使用31”理念的最初发明者(我想没有人知道谁是第一个)不需要知道它为什么会起作用。尽管如此,通过对
int
表示的
String
逐字符散列来对
int
进行散列仍然使用了一种专为文本设计的算法,这正是由于“逐字符”的性质,独立于所使用的
31
number.String.hashCode可能是hashCode()最重要的实现在整个Java世界。我相信它在中文文本上的效果和在只包含“0”和“1”的字符串上的效果一样好,因为有太多不同的程序依赖它。因此,我的建议的不足可能是构建字符串所需的开销,但如果它是string.hashCode(),我将被诅咒。
@Override
public int hashCode()
{
    final int prime = 31;
    int result = 1;
    result = prime * result + (left ==null? 0 : left.hashCode());
    result = prime * result + (right ==null? 0 : right.hashCode());
    return result;
}