Binary Shift Operations
I'll assume that you know what binary numbers are & that you are aware of the shift operators ( >> , << , >>>) in Java .
Why byte is not a byte anymore after a shift operation ?
Lets assume the following block of code -
byte b = 2;
byte c = 1;
byte d = b >> c;
When the above code is compiled you get the following compile-time error -
Incompatible type for declaration. Explicit cast needed to convert int to byte.
The reason for this is that the operands ( b & c ) are implicitly promoted to the int type before any binary operators are applied . Refer JLS 5.6.1 .
What this means -
At the time of declaration/assignment 2 is defined as 00000010 ( byte type) .
But before the shift operand is applied , 2 is converted to 0000000000000000000000000000010 ( int type) .
And since there is no implicit conversion from int to byte , the error is justified .
The same is true for short & char types as well .
Before any binary operator is, applied arithmetic promotion of operands takes place so that the operands are at least of the type int .
What is shifting anyways ?
Shifting is basically taking the binary equivalent of a number & moving the bit pattern left or right . This is analogous to a queue - one bit moves forward & leaves while the one behind takes it's place. Simple ! This is exactly what the >> & << operators do (>>> is a bit tricky ) .
Before you proceed, you might want to open Voodoo Bytes - Binary Shift Applet to help you with the shift operations that'll follow.
Try an example !
Consider 78 whose binary equivalent is
00000000 00000000 00000000 01001110 Try here!
Say you wanna shift it right ( >> ) 2 times , keeping that queue in mind , here's what we get
00000000 00000000 00000000 00010011 ( = 19 )
Similarly now lets shift left ( << ) 3 times & we get
00000000 00000000 00000010 01110000 ( = 624 )
Now for some negative values -
Lets try -65 whose binary equivalent is
11111111 11111111 11111111 10111111
Shift left ( << ) 2 times & the result is
11111111 11111111 11111110 11111100 ( = -260 )
Shift right ( >> ) 2 times & the result is
11111111 11111111 11111111 11101111 ( = -17 )
Did I miss something up there !?
When you shift left ( << ) the void left behind by the shift is filled by zero's but that's not the case when you shift right ( >> ) .
When shifting right ( >> ) the leftmost bits exposed by the right shift are filled in with previous contents of the leftmost bit . That's why when we right shifted 78 we filled it with zero's ( zero is the leftmost bit ) & when we right shifted -65 we filled it with one's ( since one was the leftmost bit ) .
As for the bits in the extreme right ( rightmost bits ) , they're discarded .
Try right shifting ( >> ) these values -
-1 = 11111111 11111111 11111111 11111111 ( result is always -1)
0 = 00000000 00000000 00000000 00000000 ( result is always 0)
Note that right shifting ( >> ) always preserves the sign of the original number i.e. to say that a negative number will stay negative while a positive number will stay positive after a right shift ( >> ).
So what about the >>> ( unsigned right shift ) operator ?
Sometimes we may require a right shift ( >> ) but we wouldn't like it to fill one's , instead we'd like it to fill zero's & only zero's no matter what . This is where the >>> ( unsigned right shift ) operator fits in .
It fills the void left behind by the leftmost bits with zero's only .
So -
78 >>> 2 = 19 &
-78 >>> 2 = 1073741804
Try here .
That's all about there is to shifting . Practice with some code samples to get a hang of the concept .