Does not compile:
void test(Integer x) {
switch (x) {
case 'a':
}
}
Compiles OK:
void test(Byte x) {
switch(x) {
case 'a':
}
}
The reasons are rather complicated, but they are all in the details (fine print if you like) of the Java Language Specification.
First of, the JLS 14.11 says the following about switch
statements:
"Every case constant associated with the switch statement must be assignment compatible with the type of the switch statement's Expression (§5.2)."
This means that 'a'
needs to be assignable to Integer
and Byte
respectively.
But that doesn't sound right:
You would think that since 'a'
should be assignable to an Integer
because char
-> int
assignment is legal. (Any char
value will fit into an int
.)
You would think that since 'a'
should NOT be assignable to an Byte
because char
-> byte
assignment is NOT legal. (Most char
values won't fit into a byte.)
In fact, neither of these is correct. To understand why, we need to read what JLS 5.2 actually about what is allowed in assignment contexts.
"Assignment contexts allow the use of one of the following:
- an identity conversion (§5.1.1)
- a widening primitive conversion (§5.1.2)
- a widening reference conversion (§5.1.5)
- a widening reference conversion followed by an unboxing conversion
- a widening reference conversion followed by an unboxing conversion, then followed by a widening primitive conversion
- a boxing conversion (§5.1.7)
- a boxing conversion followed by a widening reference conversion
- an unboxing conversion (§5.1.8)
- an unboxing conversion followed by a widening primitive conversion."
To go from 'a'
to Integer
, we would need to1 widen the char
value to an int
then box the int
to an Integer
. But if you look at the combinations of conversions that are allowed, you cannot do a widening primitive conversion followed by a boxing conversion.
Therefore 'a'
to Integer
is not allowed. This explains the compilation error in the first case.
You would think that 'a'
to Byte
is disallowed because that would involve a primitive narrowing conversion ... which is not in the list at all. In fact, literals are a special case. JLS 5.2 goes on to say the following.
"In addition, if the expression is a constant expression (§15.28) of type byte, short, char, or int:
A narrowing primitive conversion may be used if the variable is of type byte, short, or char, and the value of the constant expression is representable in the type of the variable.
A narrowing primitive conversion followed by a boxing conversion may be used if the variable is of type
Byte
,Short
, orCharacter
, and the value of the constant expression is representable in the type byte, short, or char respectively."
The second of these applies to 'a'
to Byte
, because:
'a'
is 97
decimal, which is within the range for byte
(-128
to +127
).This explains why there is no compilation error in the second example.
1 - We can't box 'a'
to a Character
and then widen Character
to Integer
because Character
is not a Java subtype of Integer
. You can only use a widening reference conversion if the source type is a subtype of the target type.
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