I understand why the following is wrong:
byte a = 3; byte b = 8; byte c = a + b; // compile error
It won't compile. Expressions always result in an int
. So we should have done the explicit cast:
byte c = (byte) (a + b); // valid code
But I don't understand why the following is correct:
byte d = 3 + 8; // it's valid! why?
Because literal integer (such as 3 or 8) is always implicitly an int
. And int-or-smaller
expressions always result in an int
too. Can anybody explain what is going on here?
The only thing I can guess is that the compiler equates this expression to the following:
byte d = 11;
and doesn't consider this an expression.
Casting between primitive types enables you to convert the value of one type to another primitive type is called Primitive Type Casting. This is most commonly occurs with the numeric data types . But boolean primitive type can never be used in a cast.
Primitive data types - includes byte , short , int , long , float , double , boolean and char.
The eight primitive data types supported by the Java programming language are: byte: The byte data type is an 8-bit signed two's complement integer. It has a minimum value of -128 and a maximum value of 127 (inclusive).
Casting Primitive Types It most commonly occurs with the numeric types, and there's one primitive type that can never be used in a cast. Boolean values must be either true or false and cannot be used in a casting operation.
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 int
s to byte
s 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
, orint
:
- A narrowing primitive conversion may be used if the type of the variable is
byte
,short
, orchar
, 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 literal42
has typeint
would mean that a cast tobyte
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".
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