I am mystified by the behavior of the Java compiler when assigning primitives to wrapper class references. Please see the code below. The lines with comments don't compile.
I don't understand the logic of why:
- a
byte
can be assigned to aByte
orShort
, but notInteger
orLong
reference - a
short
can be assigned to aByte
orShort
, but notInteger
orLong
reference - an
int
can be assigned to aByte
,Short
, orInteger
, but notLong
reference - a
long
can be assigned to aLong
, but notByte
,Short
orInteger
reference
I cannot see the pattern. Any insight into this will be really helpful. Thanks.
Byte s5 = (byte)7;
Short s6 = (byte)7;
Integer s7 = (byte)7; // Does not compile
Long s8 = (byte)7; // Does not compile
Byte s9 = (short)7;
Short s10 = (short)7;
Integer s11 = (short)7; // Does not compile
Long s12 = (short)7; // Does not compile
Byte s1 = (int)7;
Short s2 = (int)7;
Integer s3 = (int)7;
Long s4 = (int)7; // Does not compile
Byte s13 = (long)7; // Does not compile
Short s14 = (long)7; // Does not compile
Integer s15 = (long)7; // Does not compile
Long s16 = (long)7;
This seems to be compiler-specific behavior. When I paste your code into Eclipse, running Java 7, I do not see the compiler errors you report for
short
toInteger
orbyte
toInteger
.Instead, I see
byte
,short
, andint
can all be assigned toByte
,Short
, andInteger
, but notLong
, andlong
can only be assigned toLong
. Interestingly, if you change the variables to primitives instead of wrapper types, thebyte
,short
, andint
behavior doesn't change, but now the assignments from the other types tolong
also work.Given that different compilers allow different conversions, I suspect the "correct" behavior is not actually spelled out in the JLS. It seems certain conversions are done under the covers because the compiler writers considered it convenient (e.g.
byte a = (int)1
is allowed butbyte a = (int)1000
is not), not because it's a documented part of the language.From my research, I found that a byte is an 8-bit signed integer. Shorts are 16-bit signed integers. Therefore I can see why they are compatible, they are both two's complement signed integers, emphasis on signed. A long is a 64-bit integer, but it can also be unsigned (considering it has methods for comparing unsigned longs). This would probably explain why your conversions to long are causing errors - you'd be casting a signed byte to a potentially unsigned long. (Source: Reading about primitives at http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)
Let's look at the types of conversions allowed in an assignment context.
Principally:
(Note my emphasis on one.)
Most of your examples that do not compile, for example
require a widening primitive conversion followed by a boxing conversion. This is not a permitted conversion.
But then you might wonder why the following example does compile:
This is a narrowing primitive conversion followed by a boxing conversion.
This is a special case:
This special case is necessary because there is no way to express an integer literal of a type narrower than
int
.