Why does the compiler not give an error for this addition operation?
This question already has an answer here:
The answer is provided by JLS 15.26.2:
For example, the following code is correct:
short x = 3;
x += 4.6;
and results in x having the value 7 because it is equivalent to:
short x = 3;
x = (short)(x + 4.6);
So, as you can see, the latest case actually work because the addition assignment (as any other operator assignment) performs an implicit cast to the left hand type (and in your case a
is a byte
). Extending, it is equivalent to byte e = (byte)(a + b);
, which will compile happily.
While decompiling your code will explain what Java is doing, the reason why it's doing it can be generally found in the language specification. But before we go into that, we have to establish a few important concepts:
A literal numeral is always interepreted as an int
.
An integer literal is of type long if it is suffixed with an ASCII letter L or l (ell); otherwise it is of type int (§4.2.1).
A byte
can only hold an integer value between -128 and 127, inclusive.
An attempt to assign a literal that is larger than the type that can hold it will result in a compilation error. This is the first scenario you're encountering.
So we're back to this scenario: why would adding two bytes that are clearly more than what a byte can handle not produce a compilation error?
It won't raise a run-time exception because of overflow.
This is the scenario in which two numbers added together suddenly produce a very small number. Due to the small size of byte
's range, it's extremely easy to overflow; for example, adding 1 to 127 would do it, resulting in -128.
The chief reason it's going to wrap around is due to the way Java handles primitive value conversion; in this case, we're talking about a narrowing conversion. That is to say, even though the sum produced is larger than byte
, the narrowing conversion will cause information to be discarded to allow the data to fit into a byte
, as this conversion never causes a run-time exception.
To break down your scenario step by step:
a = 127
and b = 5
together to produce 132. a
and b
are of type byte
, so the result must also be of type byte
. (byte)(a += b)
. a
and z
contain the result -124 due to the wrap-around. I came to the conclusion that the result of an expression that involves variables cannot be guaranteed. The resulting value can be within or outside the byte range so compiler throws off an error.
No, that's not the reason. The compilers of a staticly-typed language work in this way: Any variable must be declared and typed, so even if its value is not known at compile-time, its type is known. The same goes for implicit constants. Based upon this fact, the rules to compute scales are basically these:
(These are in fact a simplified view; actually might be a little more complex).
Apply it to your cases:
byte d = 1 + b
The actual scales are:
byte = int + byte
... (because 1
is considered as an implicit int
constant). So, applying the first rule, the variable must have at least int
scale.
And in this case:
byte z = (a+=b);
The actual scales are:
byte = byte += byte
... which is OK.
Update
Then, why byte e = a + b
produce a compile-time error?
As I said, the actual type rules in java are more complex: While the general rules apply to all types, the primitive byte
and short
types are more restricted: The compiler assumes that adding/substracting two or more bytes/shorts is risking to cause an overflow (as @Makoto stated), so it requires to be stored as the next type in scale considered "safer": an int
.
上一篇: 将int加到short