-Integer.MIN_VALUE == Integer.MIN_VALUE but -Byte.MIN_VALUE != Byte.MIN_VALUE
Somewhat surprisingly, these two expressions evaluate to true:
-Integer.MIN_VALUE == Integer.MIN_VALUE // true
-Long.MIN_VALUE == Long.MIN_VALUE // true
Bytes and shorts however seem to behave as expected:
-Byte.MIN_VALUE == Byte.MIN_VALUE // false
-Short.MIN_VALUE == Short.MIN_VALUE // false
What’s going on here?
Explanation
Java uses two’s complement to represent integer values. In this representation the values are not symmetrical around origo. There's one more negative value than there are positive values. The smallest value has no positive counterpart! For example:
Integer.MIN_VALUE
equals −231Integer.MAX_VALUE
equals +231−1
When you try to negate −231 you get 231, which is larger than the the maximum int value, so it overflows and rolls over to the negative side.
Here’s an illustration:
In other words, Integer.MIN_VALUE
is its own negation. This causes other surprises too, such as Math.abs(Integer.MIN_VALUE)
, which is implemented as x < 0 ? -x : x
, to return a negative value.
What’s up with byte
and short
?
Byte and short values are also stored in two’s complement. Java however, does not do arithmetic directly on bytes and shorts. Instead, they are promoted to int
s, and then the unary minus is computed.
If b
is a byte, then -b
is equivalent to -((int) b)
.
One way to illustrate this is to create two overloaded methods…
void m(byte b) { System.out.println("A byte"); }
void m(int i) { System.out.println("An int"); }
…and call them as follows:
byte b = 0;
m(b); // Prints "A byte"
m(-b); // Prints "An int"
So -Byte.MIN_VALUE
equals 128, but in the form of an int
. If we cast this result back to a byte
(for which the maximum value is 127) it rolls over and becomes −128, just as in the case of ints and longs:
(byte) -Byte.MIN_VALUE == Byte.MIN_VALUE // true
(short) -Short.MIN_VALUE == Short.MIN_VALUE // true
Here’s an illustration: