b6 does work due to compile-time narrowing of literal constants. b7 does not work because compile-time narrowing is limited to all primitives but long (kind of strange, no idea why)
The interesting part is §5.2 of the JLS:
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.
If the type of the expression cannot be converted to the type of the variable by a conversion permitted in an assignment context, then a compile-time error occurs.
No idea why i
does not work though - widening should work just fine and in fact, the compiler should generate something like Integer.valueOf((byte)3);
anyhow. Using the explicit call works as expected, i.e. widening is happening.
Interestingly enough using the eclipse Java compiler Integer i = (byte) 3;
compiles just fine, which leads me to believe you just found a bug in javac - congratulations! (well either that or a bug in the eclipse compiler; but eclipse's behavior seems the correct one to me). FWIW I've reported the bug against javac to oracle..
Finding the right part in the JLS was less work than formatting this that it's somewhat readable - so probably easier if you follow the link instead.