Java allows to assign byte to java.lang.Short but not to java.lang.Integer
Asked Answered
C

1

9
final byte b = 12;  
Short s = b;  
Integer i = b;

Program compiles fine for Short but for Integer compilation fails with "incompatible types" message.

I am having difficult time trying to understand this behavior. I could not find anything for this specific scenario..

Croatian answered 13/8, 2014 at 17:27 Comment(7)
use int instead of IntegerPique
It's not a 100% duplicate because it doesn't specify why Short is allowed, but Integer isn't so I retracted the closevote. Nevertheless very related: #7014671Beauteous
In my opinion, the "very related" question doesn't have an adequate answer - it just has a bunch of people making wild speculations. I think it would be a mistake to close this.Crockett
Not only that, but the very related question's correct answer is wrong. Clearly byte is autoboxing to Short even though Short is larger than a byte. So why wouldn't byte to Integer work? Is it because it's greater than "2 levels of carelessness" higher? Seems arbitrary.Mandy
The plot thickens: Removing the 'final' keyword causes the Short autoboxing to generate a compiler error as well. That might be some clue as to the cause of this strange behavior.Rubious
And another weird nuance: Character c = b compiles just fine too. But chars are unsigned! So what happens when you change b to -12? It then fails to compile!Guesthouse
There is a good answer to this question https://mcmap.net/q/531154/-java-widening-conversionsPique
G
7

I attempted to duplicate this with a wider group of assignment contexts:

final byte b = 12;
Byte b2 = b;
Character c = b;  // Only an error if b isn't final
char c2 = b;      // Only an error if b isn't final
Short s = b;      // Only an error if b isn't final
short s2 = b;
Integer i = b;  // Error, as indicated in the question
int i2 = b;
Long l = b;     // Also an error
long l2 = b;
Float f = b;    // Also an error
float f2 = b;
Double d = b;   // Also an error
double d2 = b;

Assigning not just to a Integer, but also to a Float, a Long or a Double is also an error.

Interestingly, if the original declaration of b was NOT final, then assigning to a Character, a char, or a Short fails also.

Section 5.2 of the JLS sheds a little light on the subject of assignment contexts and their allowed conversions.

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 boxing conversion (§5.1.7) optionally followed by a widening reference conversion

  • an unboxing conversion (§5.1.8) optionally followed by a widening primitive conversion.

This covers all of the conversions to wider primitive variables, which are always allowed, whether b is final or not. (That holds unless b is negative, in which case the assignment to an unsigned char (or Character) would fail.) Continuing:

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 type of the variable is 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 type of the variable is:

    • Byte and the value of the constant expression is representable in the type byte.

    • Short and the value of the constant expression is representable in the type short.

    • Character and the value of the constant expression is representable in the type char.

Because b is final, the expression b is a constant expression, allowing it to be narrowed from the int constant expression 12 to byte, char, or short and then boxed to Byte, Character, or Short, but strangely, not to Integer or anything "above". The only possible explanation I can think of is that constant expressions that are subject to a primitive narrowing conversion aren't specifically allowed to be converted to Integer, Long, Float, or Double.

If b isn't final, then the narrowing followed by boxing isn't allowed, and a non-constant expression can't be promoted from byte to char either.

Gyrus answered 13/8, 2014 at 18:22 Comment(4)
Character c = b; // Only an error if b isn't final (or b is negative.) Great answer!Guesthouse
@MarkPeters True. As stated in the JLS quote above, "and the value of the constant expression is representable in the type of the variable". A negative final b would cause char c = b; to fail with an error also.Gyrus
but strangely, not to Integer or anything "above" I think that is to be expected since at that point you're working with Short and Integer and there is no widening possible on these wrapper types. See $JLS 5.1.5: A widening reference conversion exists from any reference type S to any reference type T, provided S is a subtype of T. and obviously there is no connection between Short and Integer directly.Beauteous
@JeroenVannevel Yes, but I found it strange that a widening primitive conversion followed by a boxing conversion isn't specifically allowed.Gyrus

© 2022 - 2024 — McMap. All rights reserved.