8

我有一个简单的自定义 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();
    }

}
4

8 回答 8

10

请不要使用字符串。这背后有很多理论和几种实现(除法,乘法等......)。如果你有大约一个小时的时间,你可以观看这个 MIT-Class

话虽如此,这就是 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,我现在生活得更快乐了。这就是它的自动 hashCode 生成产生的结果。它不那么冗长。还要注意素数的使用。

@Override
public int hashCode() {
    int result = x;
    result = 31 * result + y;
    return result;
}
于 2012-02-03T21:48:21.783 回答
5

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

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);
}

这两种 varags 方法都只是简单地委托给Arrays.hashCode(Object[] a),因此由于整数的自动装箱和创建对象引用数组而对性能有轻微影响,但它应该远没有使用反射那么重要.

而且可读性非常好,因为您可以简单地看到,哪些字段用于哈希码计算,并且所有乘法和加法语法都隐藏在以下内容中Arrays.hashCode(Object[] a)

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;
}
于 2012-02-03T22:55:30.457 回答
3

我建议使用不带字符串的更简单且性能更高的方法,也许是 Josh Bloch's method from this answer,在您的情况下只是:

return 37 * x + y;

编辑:nybbler 是正确的。实际推荐的是:

int result = 373; // Constant can vary, but should be prime
result = 37 * result + x;
result = 37 * result + y;
于 2012-02-03T21:34:17.960 回答
1

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

http://ulamspiral.com/images/IntegerSpiral.gif

@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;
}

虽然这种方法需要更多的计算,但不会发生不可预知的碰撞。它还有一个很好的特性,即越靠近原点的点通常哈希值越小。(仍然可以用 x 或 y > sqrt(MAX_VALUE) 溢出)

于 2018-05-08T07:39:36.987 回答
0

我曾经编写自己的哈希和等于函数然后我发现了这个:)

import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.EqualsBuilder;

@Override
public boolean equals(Object obj) {
   return EqualsBuilder.reflectionEquals(this, obj);
 }
@Override
public int hashCode() {
   return HashCodeBuilder.reflectionHashCode(this);
 }

当然要记住以下几点:

由于反射涉及动态解析的类型,因此无法执行某些 Java 虚拟机优化。因此,反射操作的性能比它们的非反射对应物慢,并且应该避免在性能敏感的应用程序中经常调用的代码部分中。SRC

于 2012-02-03T21:34:17.837 回答
0

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

public int hashCode() {
    long bits = java.lang.Double.doubleToLongBits(getX());
    bits ^= java.lang.Double.doubleToLongBits(getY()) * 31;
    return (((int) bits) ^ ((int) (bits >> 32)));
}

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

于 2012-02-03T21:36:35.483 回答
0

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

/**
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     }

来自: http: //kickjava.com/src/java/awt/geom/Point2D.java.htm#ixzz1lMCZCCZw

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

于 2012-02-03T21:40:28.427 回答
0

默认情况下,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 算法中加入一个素数将有助于它的“唯一性”。

于 2012-02-03T21:41:39.690 回答