Why does not give it out a compilation error or a runtime Exception?
Because the language specification mandates that arithmetic on primitive types is modulo 2^width
, so -1
becomes 2^16-1
as a char
.
In the section on integer operations, it is stated that
The built-in integer operators do not indicate overflow or underflow in any way.
so that forbids throwing an exception.
For the postfix-decrement operator used, specifically, its behaviour is specified in 15.14.3
Otherwise, the value 1 is subtracted from the value of the variable and the difference is stored back into the variable. Before the subtraction, binary numeric promotion (§5.6.2) is performed on the value 1 and the value of the variable. If necessary, the difference is narrowed by a narrowing primitive conversion (§5.1.3) and/or subjected to boxing conversion (§5.1.7) to the type of the variable before it is stored. The value of the postfix decrement expression is the value of the variable before the new value is stored.
The binary numeric promotion converts both, the value and 1, to int
(since the type here is char
), thus you have the intermediate result -1
as an int
, then the narrowing primitive conversion is performed:
A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits, where n is the number of bits used to represent type T. In addition to a possible loss of information about the magnitude of the numeric value, this may cause the sign of the resulting value to differ from the sign of the input value.
resulting in a char
value of 0xFFFF
(since Java specifies two’s complement representation for its signed integer types, explicitly stated in the specification of unary minus):
For integer values, negation is the same as subtraction from zero. The Java programming language uses two’s-complement representation for integers, and the range of two’s-complement values is not symmetric, so negation of the maximum negative int or long results in that same maximum negative number. Overflow occurs in this case, but no exception is thrown. For all integer values x, -x equals (~x)+1.
For the general wrap-around behaviour for out-of-range results, as an example in the specification of the multiplication operator:
If an integer multiplication overflows, then the result is the low-order bits of the mathematical product as represented in some sufficiently large two’s-complement format. As a result, if overflow occurs, then the sign of the result may not be the same as the sign of the mathematical product of the two operand values.
Similar phrases occur in the specification of integer addition, and subtraction is required to fulfill a - b == a + (-b)
, so the overflow behaviour follows.