簡體   English   中英

如何為包含雙字段的類實現 equals/hashCode 方法

[英]How to implement the equals/hashCode methods for classes that contain double fields

我在包含雙字段的類中覆蓋了 equals 和 hashCode。 我的第一種方法是在 equals 方法中使用 epsilon 測試,在 hashCode 中使用 Double.hashCode( double ),但這會導致相等的對象具有不同的哈希碼; 這是一個簡化的示例:

public class DoubleHashTest2
{
    public static void main(String[] args)
    {
        double  base1   = .9;
        double  base2   = .7;
        Test    test1   = new Test( base1 - .1 );
        Test    test2   = new Test( base2 + .1 );

        System.out.println( test1.equals( test2 ) );
        System.out.println( test1.hashCode() );
        System.out.println( test2.hashCode() );
    }

    private static class Test
    {
        private double  dnum1;

        public Test( double dnum1 )
        {
            this.dnum1 = dnum1;
        }

        public boolean equals( Test other )
        {
            final double    epsilon = .0001;
            boolean         result  = false;
            if ( this == other )
                result = true;
            else if ( other == null )
                result = false;
            else
                result  = Math.abs( this.dnum1 - other.dnum1 ) < epsilon;
            return result;
        }

        public int hashCode()
        {
            int hash    = Double.hashCode( dnum1 );
            return hash;
        }
    }
}

我已經想到了幾種解決方案,包括轉換為 BigDecimal,但我對其中任何一個都不滿意。 我終於決定四舍五入:

public boolean equals( Test other )
{
    boolean         result  = false;
    if ( this == other )
        result = true;
    else if ( other == null )
        result = false;
    else
    {
        double  test1   = round( dnum1 );
        double  test2   = round( other.dnum1 );
        result  = test1 == test2;
    }
    return result;
}

public int hashCode()
{
    double  temp    = round( dnum1 );
    int hash    = Double.hashCode( temp );
    return hash;
}

private double round( double dnum )
{
    // tests for NaN and +/-infinity omitted for brevity
    final int       places      = 4;
    final double    round_const = Math.pow( 10, places );
    double result   = ((int)(dnum * round_const + .5)) / round_const;
    return result;
}

但是選擇一個好的舍入算法很困難,而且這似乎有點昂貴。 我查看了類似的類,例如 Point2D.Double,但此類中的 equals 失敗,例如,在比較 .8 和 0.79999999999999999 時。

有沒有推薦的方法來處理這個問題?

回答主要問題

您不需要任何自定義舍入,因為Double類具有doubleToLongBits()方法,該方法只是將double轉換為long (它們都是 64 位值)。

此外,對於您的equals()方法,您可以使用Double#compare()比較兩個double值。

您的示例可能的equals()hashCode()

public boolean equals(Object other) {
    if (this == other) {
        return true;
    }
    if (null == other
            || this.getClass() != other.getClass()) {
        return false;
    }

    return Double.compare(this.dnum1, ((Test) other).dnum1) == 0;
}

public int hashCode() {
    long bits = Double.doubleToLongBits(this.dnum1);
    return (int) (bits ^ (bits >>> 32));
}

關於浮點運算

您的示例顯示了浮點計算double使用的缺點 - 即使大小相同的值也可以給出接近但不同的結果。 也許你應該使用BigDecimal

另外,請參閱此問題的答案。

這個怎么樣?

public static boolean equals( double param1, double param2 )
{
    final double    epsilon  = 1e-10;
    
    // accounts for 0, NaN, +/-INFINITY
    boolean result  = param1 == param2;
    if ( !result )
    {
        double quot = param1 / param2;
        result = quot > 0 && (1 - quot) < epsilon;
    }
    
    return result;
}

證明:

public static void main(String[] args)
{
    double dvar1 = 0.7 + 0.1;
    double dvar2 = 0.9 - 0.1;
    System.out.println( dvar1 == dvar2 ); // expect false
    System.out.println( equals( dvar1, dvar2 ) ); // expect true
}
@Override
public int hashCode() {
    return Double.hashCode(Math.round(dnum1));
}


public boolean equals( Object other )
{
    if(other instanceof Test)
        return equals(test);
    return false;
}
public boolean equals( Test other )
{
    if(other == null)
        return false;
    return isEqual(dnum1,other.dnum1);
}
public boolean isEqual(double number,double anotherNumber){
    if (number == anotherNumber)// eg 0, NaN, +/-INFINITY
        return true;
    return Math.abs(number - anotherNumber) <= EPSILON;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM