Number n = 10;
int i = 10;
System.out.println(n == i);
Based on "You CAN box then widen". Why the above code gives a compile time error? My guess is that if i will be first boxed to Integer and widened to Number the result will always be false. There are any specification referring to == operator when comparing a primitive with an object? Will always try to perform unboxing and the if necessarily will widen?
Per the JLS, ==
comparisons between a boxed and an unboxed value result in an unboxing conversion, not the other way around (or else you'd be using reference equality, not value equality). The compiler can't unbox a plain Number
; Number
itself isn't "convertible to a numeric type."
The Java 7 compiler appears to be being clever. The assembly output for this version and for the version in which the comparison is moved into a private
method completely ignore the declared type Number
, and everything works properly. Make that method public
, and the behavior is as specified: The conversion isn't one of the listed types for which unboxing will occur, and the compiler boxes 10
to an Integer
and compares by reference, meaning that if you try using Integer.valueOf(10)
, you'll get true
for the range -128..127, and if you use anything else (another width, new Integer(10)
), you'll get false
.
Output from your code (note that Number
appears nowhere, and that you're getting comparison based on reference equality in line 18; try using L
or casting to short
):
public static void main(java.lang.String[]);
Code:
0: bipush 10
2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
6: bipush 10
8: istore_2
9: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
12: aload_1
13: bipush 10
15: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
18: if_acmpne 25
21: iconst_1
22: goto 26
25: iconst_0
26: invokevirtual #4 // Method java/io/PrintStream.println:(Z)V
29: return
Version that prevents optimization:
public class Test
{
public static void main(String[] args)
{
Number n = new Integer(10);
compare(n);
}
public static void compare(Number n)
{
int i=10;
System.out.println(n == 10);
}
}
Assembly; note that you're still getting a reference comparison in line 12:
public static void main(java.lang.String[]);
Code:
0: new #2 // class java/lang/Integer
3: dup
4: bipush 10
6: invokespecial #3 // Method java/lang/Integer."<init>":(I)V
9: astore_1
10: aload_1
11: invokestatic #4 // Method compare:(Ljava/lang/Number;)V
14: return
public static void compare(java.lang.Number);
Code:
0: bipush 10
2: istore_1
3: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
6: aload_0
7: bipush 10
9: invokestatic #6 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
12: if_acmpne 19
15: iconst_1
16: goto 20
19: iconst_0
20: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
23: return
The code in your question gives me "Incompatible operand types Number and int" with Java 6 and 7 using the Eclipse compiler. With javac
from Oracle's Java 7 SDK, it compiles and prints true
.
Why?
The assignment Number n = 10
will be converted into Number n = Integer.valueOf(10);
Later, the compiler will create n == Integer.valueOf(10)
(autoboxing the int value).
This gives true because Integer.valueOf()
keeps an internal cache for small integer numbers and always returns the same instance for them:
Integer.valueOf(10) == Integer.valueOf(10)
But this is a just a side effect of the implementation, you should not rely on it.
Bytecode:
public static void main(java.lang.String[]);
Code:
0: bipush 10
2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
6: bipush 10
8: istore_2
9: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
12: aload_1
13: iload_2
14: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
17: if_acmpne 24
20: iconst_1
21: goto 25
24: iconst_0
25: invokevirtual #4 // Method java/io/PrintStream.println:(Z)V
28: return
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With