Comparing doubles in Java gives odd results

Simeon picture Simeon · Mar 8, 2011 · Viewed 20.2k times · Source

I really can'get my head around why the following happens:

Double d = 0.0;
System.out.println(d == 0); // is true
System.out.println(d.equals(0)); // is false ?!

This however works as expected:

Double d = 0.0;
System.out.println(d == 0.0); // true
System.out.println(d.equals(0.0)); // true

I'm positive that this is related to autoboxing in some way, but I really don't know why 0 would be boxed differently when the == operator is used and when .equals is called.

Doesn't this implicitly violate the equals contract ?

  *  It is reflexive: for any non-null reference value
  *     x, x.equals(x) should return
  *     true.

EDIT:

Thanks for the fast answers. I figured that it is boxed differently, the real question is: why is it boxed differently ? I mean that this would be more intuitive if d == 0d than d.equals(0d) is intuitive and expected, however if d == 0 which looks like an Integer is true than 'intuitively' d.equals(0) should also be true.

Answer

jmj picture jmj · Mar 8, 2011

just change it to

System.out.println(d.equals(0d)); // is false ?! now true

You were comparing double with Integer 0

Under the cover

System.out.println(d.equals(0)); // is false ?!

0 will be autoboxed to Integer and an instance of Integer will be passed to equals() method of Double class, where it will compare like

@Override
    public boolean equals(Object object) {
        return (object == this)
                || (object instanceof Double)
                && (doubleToLongBits(this.value) == doubleToLongBits(((Double) object).value));
    }

which is going to return false of course.

Update

when you do comparison using == it compares values so there is no need to autobox , it directly operates on value. Where equals() accepts Object so if you try to invoke d1.equals(0) , 0 is not Object so it will perform autoboxing and it will pack it to Integer which is an Object.