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.
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.
Number
objects only equal to numbers with the same value if they are of the same type. That is:
new Double(0).equals(new Integer(0));
new BigInteger("0").equals(new BigDecimal("0"));
and similar combinations are all false.
In your case, the literal 0
is boxed into an Integer
object.
It's probably worth noting that you should compare floating point numbers like this:
|x - y| < ε, ε very small
d.equals(0)
: 0
is an int
. The Double.equals()
code will return true only for Double
objects.
When you perform
d == 0
this is upcast to
d == 0.0
however there are no upcasting rules for autoboxing and even if there were equals(Object) gives no hits that you want a Double instead of an Integer.