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:
byte
can be assigned to a Byte
or Short
, but not Integer
or Long
referenceshort
can be assigned to a Byte
or Short
, but not Integer
or Long
referenceint
can be assigned to a Byte
, Short
, or Integer
, but not Long
referencelong
can be assigned to a Long
, but not Byte
, Short
or Integer
referenceI 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;
Let's look at the types of conversions allowed in an assignment context.
Principally:
Assignment contexts allow the use of one of the following:
an identity conversion
a widening primitive conversion
a widening reference conversion
a boxing conversion optionally followed by a widening reference conversion
an unboxing conversion optionally followed by a widening primitive conversion.
(Note my emphasis on one.)
Most of your examples that do not compile, for example
Integer s11 = (short)7;
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:
Byte s9 = (short)7;
This is a narrowing primitive conversion followed by a boxing conversion.
This is a special case:
In addition, if the expression is a constant expression of type
byte
,short
,char
, orint
[...] a narrowing primitive conversion followed by a boxing conversion may be used if the type of the variable is:
Byte
and the value of the constant expression is representable in the typebyte
.
Short
and the value of the constant expression is representable in the typeshort
.
Character
and the value of the constant expression is representable in the typechar
.
This special case is necessary because there is no way to express an integer literal of a type narrower than int
.
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
to Integer
or byte
to Integer
.
Instead, I see byte
, short
, and int
can all be assigned to Byte
, Short
, and Integer
, but not Long
, and long
can only be assigned to Long
. Interestingly, if you change the variables to primitives instead of wrapper types, the byte
, short
, and int
behavior doesn't change, but now the assignments from the other types to long
also work.
javac 1.7.0_02
| byte | Byte || short | Short || int | Integer || long | Long |
From byte | Yes | Yes || Yes | Yes || Yes | No || Yes | No |
From short | Yes | Yes || Yes | Yes || Yes | No || Yes | No |
From int | Yes | Yes || Yes | Yes || Yes | Yes || Yes | No |
From long | No | No || No | No || No | No || Yes | Yes |
Eclipse Indigo
| byte | Byte || short | Short || int | Integer || long | Long |
From byte | Yes | Yes || Yes | Yes || Yes | Yes || Yes | No |
From short | Yes | Yes || Yes | Yes || Yes | Yes || Yes | No |
From int | Yes | Yes || Yes | Yes || Yes | Yes || Yes | No |
From long | No | No || No | No || No | No || Yes | Yes |
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 but byte a = (int)1000
is not), not because it's a documented part of the language.
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