Primitive cast and assignments in Java

This has less† to do with whether or not 3 + 8 is evaluated to 11 at compile-time, and more to do with the fact the compiler is explicitly permitted to implicitly narrow ints to bytes in certain cases. In particular, the language specification explicitly permits implicit narrowing conversions to byte of constant expressions of type int that can fit in a byte at compile-time.

The relevant section of the JLS here is section §5.2:

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.

The compile-time narrowing of constants means that code such as: byte theAnswer = 42; is allowed. Without the narrowing, the fact that the integer literal 42 has type int would mean that a cast to byte would be required:

†: Obviously, as per the specification, the constant expression needs to be evaluated to see if it fits in the narrower type or not. But the salient point is that without this section of the specification, the compiler would not be permitted to make the implicit narrowing conversion.

Let's be clear here:

byte a = 3; 
byte b = 8; 

The reason that these are permitted is because of the above section of the specification. That is, the compiler is allowed to make the implicit narrowing conversion of the literal 3 to a byte. It's not because the compiler evaluates the constant expression 3 to its value 3 at compile-time.


The only thing I can guess is that the compiler equates this expression to the following:

Yes it does. As long as the right side expression is made of constants (which fit into the required primitive type -- see @Jason's answer for what the JLS says about this exactly), you can do that. This will not compile because 128 is out of range:

byte a = 128;

Note that if you transform your first code snippet like this:

final byte a = 3; 
final byte b = 8; 
byte c = a + b;

it compiles! As your two bytes are final and their expressions are constants, this time, the compiler can determine that the result will fit into a byte when it is first initialized.

This, however, will not compile:

final byte a = 127; // Byte.MAX_VALUE
final byte b = 1;
byte c = a + b // Nope...

The compiler will error out with a "possible loss of precision".


It is because 3 and 8 are compile time constants.

Therefore, at the time of compilation happens, compiler can identify that 3 + 8 can fit into a byte variable.

If you make your a and b to final (constant) variable. a + b will become a compile time constant. Therefore, it will compile without any issue.

    final byte a = 3;
    final byte b = 8;
    byte c = a + b;