I think the simplest way to explain this would just be to break it down into the order of operations you are performing
Instance | # int | char | # byte | result |
Source | 11 11 11 11 | 11 11 11 11 | 11 11 11 11 | 11 11 11 10 | -2 |
byte |(11 11 11 11)|(11 11 11 11)|(11 11 11 11)| 11 11 11 10 | -2 |
int | 11 11 11 11 | 11 11 11 11 | 11 11 11 11 | 11 11 11 10 | -2 |
char |(00 00 00 00)|(00 00 00 00)| 11 11 11 11 | 11 11 11 10 | 65534 |
int | 00 00 00 00 | 00 00 00 00 | 11 11 11 11 | 11 11 11 10 | 65534 |
- You are simply taking a 32bit signed value.
- You are then converting it to an 8bit signed value.
- When you attempt to convert it to a 16bit unsigned value, the compiler sneaks in a quick conversion to 32bit signed value,
- Then converting it to 16bit without maintaining sign.
- When the final conversion to 32bit occurs, there is no sign, so the value adds zero bits to maintain value.
So, yes, when you look at it this way, the byte cast is significant (academically speaking), though the result is insignificant (joy to programming, a significant action can have an insignificant effect). The effect of narrowing and widening while maintaining sign. Where, the conversion to char narrows, but does not widen to sign.
(Please note, I used a # to denote the Signed bit, and as noted, there is no signed bit for char, as it is an unsigned value).
I used parens to represent what is actually happening internally. The data types are actually trunked in their logical blocks, but if viewed as in int, their results would be what the parens symbolize.
Signed values always widen with value of the signed bit. Unsigned always widen with the bit off.
*So, the trick (or gotchas) to this, is that the expansion to int from byte, maintains the signed value when widened. Which is then narrowed the moment it touches the char. This then turns off the signed bit.
If the conversion to int did not occur, the value would have been 254. But, it does, so it isn't.
byte
cast doesn't change the result doesn't mean its not doing anything... – MallinaSystem.out.println((int)(char)(byte)-130)
and see if it's "just" 65536-130. Then read @Chris K answer and work it out! :) – Mallinabyte
cast! – Mallina(byte)
indeed changes the result, so it's a different situation. – Cruzeirobyte
cast isn't insignificant as the OP stated. He was "lucky" that in his case the cast had no effect on the result, but as you can see from various answers something is indeed going on there... – Mallina(byte)
is needed, but if we are already in the range -128..127, we don't need it, so then it is insignificant. – Cruzeiro(byte)
cast does nothing, except constrain the number to the byte range. The overall effect does not rely on the byte cast. – Sedentary