Java – how to implement the equals / hashcode method for a class with two fields
I override equals and hashcode in a class that contains two fields My first method is to use epsilon test in equals method and double in hashcode Hashcode (double), but this will result in equal objects with different hash codes; This is a simplified example:
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; } } }
I've thought about several solutions, including converting to BigDecimal, but I'm not satisfied with any of them I finally decided to round:
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; }
But choosing a good rounding algorithm is difficult, and it seems expensive I looked at similar classes, such as point2d Double, but equals in this class fails, for example, when comparing. 8 with 0.799999999999999
Is there a recommended way to deal with this problem?
Solution
Answer the main questions
You don't need any custom rounding, because the double class has the doubletolongbits () method, which just converts double to long (both 64 bit values)
In addition, for the equals () method, you can compare two double values with double #compare ()
Your example might use equals () and 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)); }
About floating point operations
Your example shows the disadvantage of the dual use of floating point calculations - even values with the same amplitude can give close but different results Maybe you should use BigDecimal?
See also the answer to this question