加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 如何为包含双字段的类实现equals / hashCode方法

发布时间:2020-12-15 02:20:23 所属栏目:Java 来源:网络整理
导读:我在包含双字段的类中重写equals和hashCode.我的第一种方法是在equals方法中使用epsilon测试,在hashCode中使用Double.hashCode(double),但这会导致具有不同哈希码的相等对象;这是一个简化的例子: public class DoubleHashTest2{ public static void main(St
我在包含双字段的类中重写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.7999999999999999时.

是否有推荐的方法来处理这个问题?

解决方法

回答主要问题

您不需要任何自定义舍入,因为Double类具有doubleToLongBits()方法,它只是将double转换为long(两者都是64位值).

此外,对于equals()方法,您可以将两个double值与Double#compare()进行比较.

您的示例可能使用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));
}

关于浮点运算

您的示例显示了浮点计算的双重使用的缺点 – 即使具有相同幅度的值也可以给出接近但不同的结果.也许你应该使用BigDecimal?

另请参阅this question答案.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读