Comparing Object and int in Java 7
Asked Answered
B

1

15

I recently stumbled on a question that made me stop and think...

To me, the code below should always trigger an error, but when one of my colleagues asked me why Eclipse didn't show one, I couldn't answer anything.

class A {
    public static void main(String... args) {
        System.out.println(new Object() == 0);
    }
}

I've investigated and found that with source level 1.6 it indeed throws an error:

incomparable types: Object and int

But now in 1.7 it compiles ok.

Please, what new feature does warrant this behavior?

Brennan answered 29/8, 2013 at 0:0 Comment(0)
A
9

What do you mean by "what new feature does warrant this behavior?" ? 1.7 is fixing an issue present in 1.6. new Object() == 0 should have never produced an error, and always caused autoboxing to trigger.

There was simply no reason why

Object a= 5 ;

was correct, and not the expression

a == 3

or even

a == 5

It was extremely weird and, IMHO, contradictory with the language specification itself.

From a dynamic point of view, though, a == 5 still evaluates to false while (Integer)a == 5 or even (int)a == 5 evaluate to true. Reason is that autounboxing was designed to never produce ClassCastExceptions and thus occur for wrapper types only, statically. The later two cases are explicit casts so ClassCastExceptions are generally allowed.

Apfel answered 29/8, 2013 at 0:5 Comment(15)
Do you mean it now is equivalent with new Object() == null and that new Object() == 2 still triggers an error?Profitsharing
It should be more or less equivalent to new Object() == new Integer(0) (or new Integer(2)). It should never be an error, and always be false since the new Object can't be the same object as the Integer object.Micromho
@MartijnCourteaux Not really. It's equivalent to new Object() == Integer.valueOf(0) and new Object() == Integer.valueOf(2). Both will always produce false, of course.Apfel
As I think about it, it was technically a bug in 1.6. But I think it will cause more trouble because the compiler won't warn you if you accidentally write something like this, instead of having the benefit of being allowed to write a == 3.Profitsharing
Would this mean that in Object a = 10000; boolean b = a == 10000;, b would be false? Because the Integer.valueOf cache only goes to 128.Profitsharing
@MartijnCourteaux Good point. Compilers usually produce warnings for every autobox, but many people disables them almost by default, so we couldn't count on them. On the other hand, you can make a similar mistake with references instead of numbers, and also this happens only with the Object class (and maybe Number). Given that generics almost completely eliminated the (explicit) use of Object, the problem could be smaller than we think.Apfel
@MartijnCourteaux You keep making good points. Yes: in Object a = 10000; boolean b = a == 10000;, b would be false. But in Integer a = 10000; boolean b = a == 10000;, b would be... true!!! (because of the autounboxing rules).Apfel
What is the reason for that? Is are any JLS section about this?Profitsharing
I'm sorry, I made a typo in my first ideone. Here is an updated version. So this means that instead of auto-boxing, auto-unboxing takes place in the last case of this test: ideone.com/FSAWxeProfitsharing
John Skeet found a reference to this behavior in the JLS. Check out his great answer here: https://mcmap.net/q/48069/-how-can-i-properly-compare-two-integers-in-java. Everything is clear to me now :)Profitsharing
@MartijnCourteaux That discussion is marginally related, as it refers to wrapper/wrapper comparisons and how to "make them work". That has always been very clear. Here we are talking reference / primitive. Specially Object / primitive. The referenced JLS chapters are obviously related because they are the ones on conversions and expressions.Apfel
Yes, I know. I just linked this answer because of the references to the JLS he put there. These JLS references explain why Integer i = 1000; boolean b = i == 1000; gives true.Profitsharing
@MartijnCourteaux You and Mario, thanks for your comments, but I think it doesn't really answer my question. Does java 7 have a new major feature that supports and explains this behavior? Or is it just a hidden fix?Brennan
looks like JDK 1.8.* treats this as error again. (I personally think that it's good — code like this is a strong smell anyway)Vicissitude
A well-designed language will allow certain type conversions to be applied in some contexts but forbidden in others. The simplistic notion that type conversions which are applicable anywhere should be applicable everywhere means that double a=1234567890/10.0f; will silently yield 123456792.0 rather than demanding that the programmer indicate more affirmatively what's really intended. Accepting the notion that operators like == should be pickier than some others will make it practical to have conversion rules which are much more useful than would be rules that must apply everywhere.Toback

© 2022 - 2024 — McMap. All rights reserved.