Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/394.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
点类的Java哈希代码_Java_Hashcode_Hash Code Uniqueness - Fatal编程技术网

点类的Java哈希代码

点类的Java哈希代码,java,hashcode,hash-code-uniqueness,Java,Hashcode,Hash Code Uniqueness,我有一个简单的自定义Point类,如下所示,我想知道我的hashCode实现是否可以改进,或者这是否是它将得到的最好的实现 public class Point { private final int x, y; public Point(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; }

我有一个简单的自定义Point类,如下所示,我想知道我的hashCode实现是否可以改进,或者这是否是它将得到的最好的实现

public class Point 
{
    private final int x, y;

    public Point(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

    public int getX() 
    {
        return x;
    }

    public int getY()
    {
        return y;
    }

    @Override
    public boolean equals(Object other) 
    {
        if (this == other)
          return true;

        if (!(other instanceof Point))
          return false;

        Point otherPoint = (Point) other;
        return otherPoint.x == x && otherPoint.y == y;
    }


    @Override
    public int hashCode()
    {
        return (Integer.toString(x) + "," + Integer.toString(y)).hashCode();
    }

}

我曾经写过自己的hash和equals函数,后来我发现:)

当然,请记住以下几点:

因为反射涉及动态解析的类型, 无法执行某些Java虚拟机优化。 因此,反射操作的性能比其 非反射副本,并且应在代码部分避免使用 在性能敏感的应用程序中经常调用


我建议使用一种更简单、性能更高的不带字符串的方法,可能是Josh Bloch的方法,在您的例子中:

return 37 * x + y;
编辑:nybbler是正确的。实际上建议的是:

int result = 373; // Constant can vary, but should be prime
result = 37 * result + x;
result = 37 * result + y;

来自JDK的Point类(继承自Point2d):


这看起来比您的实现略好。

您可以查看现有的点类型类实现:

/**
343      * Returns the hashcode for this <code>Point2D</code>.
344      * @return a hash code for this <code>Point2D</code>.
345      */
346     public int hashCode() {
347     long bits = java.lang.Double.doubleToLongBits(getX());
348     bits ^= java.lang.Double.doubleToLongBits(getY()) * 31;
349     return (((int) bits) ^ ((int) (bits >> 32)));
350     }
发件人:


可以找到hashCode实现的简单指南

默认情况下,Eclipse将为您的Point类使用hashCode()函数,类似于:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + getOuterType().hashCode();
    result = prime * result + x;
    result = prime * result + y;
    return result;
}

至少,在hashCode算法中加入素数将有助于它的“唯一性”。

请不要使用字符串。这背后有很多理论和一些实现(除法、乘法等)。如果你有一个小时的时间,你可以看这个

话虽如此,以下是Netbeans 7.1的建议:

@Override
public int hashCode() {
    int hash = 7;
    hash = 71 * hash + this.x;
    hash = 71 * hash + this.y;
    return hash;
}
2015年10月编辑

不久前我开始使用IntelliJ,现在我生活得更快乐了。这就是它的自动哈希代码生成所产生的结果。没那么冗长了。注意素数的使用

@Override
public int hashCode() {
    int result = x;
    result = 31 * result + y;
    return result;
}

Gevorg建议的所有有效成员字段值的手动乘法可能是最有效的,并且具有良好的值分布。然而,如果您喜欢可读性,那么在Java7中也有不错的替代方案

import java.util.Objects;

...

@Override
public int hashCode() {
    return Objects.hash(x, y);
}
。。。或在图书馆:

这两种varags方法都只是简单地委托给,因此由于int的自动装箱和创建对象引用数组,对性能的影响很小,但是它应该远没有使用反射那么重要

可读性非常好,因为您可以简单地看到,哪些字段用于hashcode计算,所有乘法和加法语法都隐藏在
数组的遮罩下。hashcode(Object[]a)


将2D点散列为单个整数的一种非常好的方法是使用数字螺旋

@覆盖
公共int hashCode(){
int ax=数学绝对值(x);
int ay=数学绝对值(y);
如果(ax>ay&&x>0)返回4*x*x-3*x+y+1;

如果(ax>ay&&x sqrt(最大值)

你打算如何改进它?你想让它更快吗?你想保证唯一性?速度?我想保证两个:)因为只有两个字段,你也可以使用这个库,但要明确列出字段。如果这个类在集合中被大量使用,反射哈希代码将是一个巨大的性能打击。我想d建议改为使用该方法。这与链接答案中的建议不完全一样。您没有注意到应该对每个字段单独执行此操作,而不是同时执行。此算法为[0,37]和[1,0]生成相同的结果。请注意,新实现仍然会为表单中的任何一对点生成冲突(x,37y),(y,37x)…+1有趣的是,Netbeans提出了与eclipse不同的建议,但实现的基础是相似的和可靠的。我很困惑,第二个实现如何是一个好的实现?即使是非常小的数字,比如(0,31),(1,0)也会发生冲突.这似乎非常有害,不是吗?@ChristopherShroba你的评论非常有趣,我度假回来后会调查一下!主要问题是,
result
在给定示例输入的情况下是用
0
初始化的。不过,IntelliJ 2016就是这样做的……对,表单的任何点都会发生冲突(a,31b),(b,31a)。感谢您的回复!我很想在您有机会的时候听听您对此的看法!@ChristopherShroba我认为问题是由0初始化的结果引起的,这也是错误的…但是,Netbeans实现也不能免疫
(a,71b),(b,71a)
攻击…想法?也许您写错了“Java”而不是“Eclipse”。默认情况下,
hashCode
“通常通过将对象的内部地址转换为整数来实现。”@MatthewFlaschen确实是这样做的。现在更新了;感谢您捕捉到了这一点。仍然容易受到
(x,31y),(y,31x)
形式的任何对的攻击,例如(0,31),(1,0)或(3,217),(7,93)。我试图在这里引发一个问题范围的讨论。有没有一种方法可以实现更健壮的实现,或者只使用2个整数来处理此类问题(这取决于哈希代码生成中使用的素数)?向所有使用此标识的人发出警告。哈希冲突是现实情况…例如,pastebin.com/6wM3W3Wv
@Override
public int hashCode() {
    int result = x;
    result = 31 * result + y;
    return result;
}
import java.util.Objects;

...

@Override
public int hashCode() {
    return Objects.hash(x, y);
}
import com.google.common.base.Objects;

....

@Override
public int hashCode() {
    return Objects.hashCode(x, y);
}
public static int hashCode(Object a[]) {
    if (a == null)
        return 0;

    int result = 1;

    for (Object element : a)
        result = 31 * result + (element == null ? 0 : element.hashCode());

    return result;
}
@Override
public int hashCode() {
    int ax = Math.abs(x);
    int ay = Math.abs(y);
    if (ax>ay && x>0) return 4*x*x-3*x+y+1;
    if (ax>ay && x<=0) return 4*x*x-x-y+1;
    if (ax<=ay && y>0) return 4*y*y-y-x+1;
    return 4*y*y-3*y+x+1;
}