简体   繁体   English

Point类的Java hashCode

[英]Java hashCode for a Point class

I have a simple custom Point class as follows and I would like to know if my hashCode implemention could be improved or if this is the best it's going to get. 我有一个简单的自定义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();
    }

}

Please do not use Strings. 请不要使用字符串。 There's a lot of theory behind this and several implementations (division method, multiplication one, etc...). 这背后有很多理论和几个实现(除法,乘法等等)。 If you have about a hour you can watch this MIT-Class 如果你有大约一个小时,你可以看这个麻省理工学院班级

This being said, here is what Netbeans 7.1 suggests: 话虽这么说,这是Netbeans 7.1建议的:

@Override
public int hashCode() {
    int hash = 7;
    hash = 71 * hash + this.x;
    hash = 71 * hash + this.y;
    return hash;
}

October 2015 Edit 2015年10月编辑

I started using IntelliJ a while back, I live happier now. 我开始使用IntelliJ了一段时间,现在我的生活更幸福。 This is what its automatic hashCode generation produces. 这就是它的自动hashCode生成。 It's a little less verbose. 它有点不那么冗长。 Note the use of prime numbers as well. 注意使用素数也是如此。

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

The manual multiplication of values of all significant member fields as suggested by Gevorg is probably the most efficient and has a good value distribution. Gevorg建议的所有重要成员字段的值的手动乘法可能是最有效的并且具有良好的价值分布。 However, if you favour readability, there are nice alternatives available either in Java 7... 但是,如果您喜欢可读性,那么Java 7中提供了很好的替代方案......

import java.util.Objects;

...

@Override
public int hashCode() {
    return Objects.hash(x, y);
}

... or in the Guava library: ......或在番石榴图书馆:

import com.google.common.base.Objects;

....

@Override
public int hashCode() {
    return Objects.hashCode(x, y);
}

Both of these varags methods simply delegate to Arrays.hashCode(Object[] a) , so there is a slight impact on performance because of the autoboxing of ints and creating an array of object references, but it should be far less significant than using reflection. 这两个varags方法都只是委托给Arrays.hashCode(Object [] a) ,所以由于int的自动装箱和创建一个对象引用数组会对性能产生轻微影响,但它应该远远不如使用反射。

And the readability is just great, since you simply see, which fields are used for the hashcode computation and all the multiply and add syntax is just hidden under the hood of 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;
}

I would recommend using a simpler and more performant method without strings, perhaps Josh Bloch's method from this answer , in your case just: 我建议使用一个更简单,更高效的方法,没有字符串,也许Josh Bloch的方法来自这个答案 ,在你的情况下:

return 37 * x + y;

EDIT: nybbler is correct. 编辑:nybbler是正确的。 What is actually recommended is: 实际建议的是:

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

A really nice way to hash a 2D point into a single integer is to use a number spiral! 将2D点散列为单个整数的一种非常好的方法是使用数字螺旋!

http://ulamspiral.com/images/IntegerSpiral.gif 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;
}

While this method requires a few more calculations, there will be no unpredictable collisions. 虽然这种方法需要更多的计算,但不会发生不可预测的碰撞。 It also has the nice property that points closer to the origin in general will have smaller hash value. 它还有一个很好的属性,一般来说,靠近原点的点会有较小的哈希值。 (Still can overflow with x or y > sqrt(MAX_VALUE) however) (仍然可以溢出x或y> sqrt(MAX_VALUE))

I used to write my own hash and equals functions then I found this : ) 我曾经写过自己的哈希和等于函数然后我发现了这个:)

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

of course keep in mind the following: 当然要记住以下几点:

Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. 由于反射涉及动态解析的类型,因此无法执行某些Java虚拟机优化。 Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications. 因此,反射操作的性能低于非反射操作,并且应避免在性能敏感应用程序中频繁调用的代码段中。 SRC SRC

From the JDK's Point class (inherited from Point2d): 从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)));
}

That looks slightly better than your implementation. 这看起来比你的实现略胜一筹。

You can have a look into existing Point type classes implementations: 您可以查看现有的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     }

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

Simple guide for hashCode implementation can be found here 可以在此处找到hashCode实现的简单指南

By default, Eclipse will use a hashCode() function for your Point class similar to: 默认情况下,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;
}

At the very least, incorporating a prime number into your hashCode algorithm will help with it's "uniqueness". 至少,在您的hashCode算法中加入素数将有助于它的“唯一性”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM