移位操作符也操纵二进制位,它们只能用来处理基本类型里的整数类型。左移位操作符(<<)会将操作符左侧的操作数向左移动,移动的位数在操作符右侧指定(低位补 0)。“有符号” 的右移位操作符(>>)则按照操作符右侧指定的位数将操作符左侧的操作数向右移动。“有符号” 的右移位操作符使用了 “符号扩展”:如果符号为正,则在高位插入 0,否则在高位插入 1。Java 还新增加了一种 “无符号” 的右移位操作符(>>>),它使用 “零扩展”:无论符号为正还是为负,都在高位插入 0。这一操作符是 C 或 C++ 中所没有的。

    如果对 char、byte 或者 short 类型的数值进行移位运算,在移位操作前它们会被转换为 int 类型,并且结果也是 int 类型。右端的可移位数中只会用到低 5 位。这样可防止我们移位超过 int 型值所具有的位数。如果处理的是 long 类型,最后得到的结果也是 long 类型。此时只会用到右端指定移位数值的低 6 位,这样移位操作就不会超出 long 类型的最大位数。

    移位操作符可以与等号组合使用( <<=、>>= 或 >>>= )。操作符左边的值会移动右边指定的位数,然后再将得到的结果赋给左边的变量。但 “无符号” 右移位操作符结合赋值操作符可能会遇到一个问题:如果对 byte 或 short 值进行移位运算,得到的可能不是正确的结果。它们会先被提升为 int 类型,进行右移操作,然后在被赋回给原来的变量时被截断,这时得到结果是 -1。下面是一个示例:

    1. // operators/URShift.java
    2. // 无符号右移测试
    3. public class URShift {
    4. public static void main(String[] args) {
    5. int i = -1;
    6. System.out.println(Integer.toBinaryString(i));
    7. i >>>= 10;
    8. System.out.println(Integer.toBinaryString(i));
    9. long l = -1;
    10. System.out.println(Long.toBinaryString(l));
    11. l >>>= 10;
    12. System.out.println(Long.toBinaryString(l));
    13. short s = -1;
    14. System.out.println(Integer.toBinaryString(s));
    15. s >>>= 10;
    16. System.out.println(Integer.toBinaryString(s));
    17. byte b = -1;
    18. System.out.println(Integer.toBinaryString(b));
    19. b >>>= 10;
    20. System.out.println(Integer.toBinaryString(b));
    21. b = -1;
    22. System.out.println(Integer.toBinaryString(b));
    23. System.out.println(Integer.toBinaryString(b>>>10));
    24. }
    25. }
    26. /* 输出:
    27. 11111111111111111111111111111111
    28. 1111111111111111111111
    29. 1111111111111111111111111111111111111111111111111111111111111111
    30. 111111111111111111111111111111111111111111111111111111
    31. 11111111111111111111111111111111
    32. 11111111111111111111111111111111
    33. 11111111111111111111111111111111
    34. 11111111111111111111111111111111
    35. 11111111111111111111111111111111
    36. 1111111111111111111111
    37. */

    在最后一个移位运算中,结果没有赋回给 b,而是直接打印了出来,所以是正确的。
    下面这个示例演示了所有涉及位操作的操作符:

    1. // operators/BitManipulation.java
    2. // 使用按位操作符
    3. import java.util.*;
    4. public class BitManipulation {
    5. public static void main(String[] args) {
    6. Random rand = new Random(47);
    7. int i = rand.nextInt();
    8. int j = rand.nextInt();
    9. printBinaryInt("-1", -1);
    10. printBinaryInt("+1", +1);
    11. int maxpos = 2147483647;
    12. printBinaryInt("maxpos", maxpos);
    13. int maxneg = -2147483648;
    14. printBinaryInt("maxneg", maxneg);
    15. printBinaryInt("i", i);
    16. printBinaryInt("~i", ~i);
    17. printBinaryInt("-i", -i);
    18. printBinaryInt("j", j);
    19. printBinaryInt("i & j", i & j);
    20. printBinaryInt("i | j", i | j);
    21. printBinaryInt("i ^ j", i ^ j);
    22. printBinaryInt("i << 5", i << 5);
    23. printBinaryInt("i >> 5", i >> 5);
    24. printBinaryInt("(~i) >> 5", (~i) >> 5);
    25. printBinaryInt("i >>> 5", i >>> 5);
    26. printBinaryInt("(~i) >>> 5", (~i) >>> 5);
    27. long l = rand.nextLong();
    28. long m = rand.nextLong();
    29. printBinaryLong("-1L", -1L);
    30. printBinaryLong("+1L", +1L);
    31. long ll = 9223372036854775807L;
    32. printBinaryLong("maxpos", ll);
    33. long lln = -9223372036854775808L;
    34. printBinaryLong("maxneg", lln);
    35. printBinaryLong("l", l);
    36. printBinaryLong("~l", ~l);
    37. printBinaryLong("-l", -l);
    38. printBinaryLong("m", m);
    39. printBinaryLong("l & m", l & m);
    40. printBinaryLong("l | m", l | m);
    41. printBinaryLong("l ^ m", l ^ m);
    42. printBinaryLong("l << 5", l << 5);
    43. printBinaryLong("l >> 5", l >> 5);
    44. printBinaryLong("(~l) >> 5", (~l) >> 5);
    45. printBinaryLong("l >>> 5", l >>> 5);
    46. printBinaryLong("(~l) >>> 5", (~l) >>> 5);
    47. }
    48. static void printBinaryInt(String s, int i) {
    49. System.out.println(
    50. s + ", int: " + i + ", binary:\n " +
    51. Integer.toBinaryString(i));
    52. }
    53. static void printBinaryLong(String s, long l) {
    54. System.out.println(
    55. s + ", long: " + l + ", binary:\n " +
    56. Long.toBinaryString(l));
    57. }
    58. }
    59. /* 输出(前32行):
    60. -1, int: -1, binary:
    61. 11111111111111111111111111111111
    62. +1, int: 1, binary:
    63. 1
    64. maxpos, int: 2147483647, binary:
    65. 1111111111111111111111111111111
    66. maxneg, int: -2147483648, binary:
    67. 10000000000000000000000000000000
    68. i, int: -1172028779, binary:
    69. 10111010001001000100001010010101
    70. ~i, int: 1172028778, binary:
    71. 1000101110110111011110101101010
    72. -i, int: 1172028779, binary:
    73. 1000101110110111011110101101011
    74. j, int: 1717241110, binary:
    75. 1100110010110110000010100010110
    76. i & j, int: 570425364, binary:
    77. 100010000000000000000000010100
    78. i | j, int: -25213033, binary:
    79. 11111110011111110100011110010111
    80. i ^ j, int: -595638397, binary:
    81. 11011100011111110100011110000011
    82. i << 5, int: 1149784736, binary:
    83. 1000100100010000101001010100000
    84. i >> 5, int: -36625900, binary:
    85. 11111101110100010010001000010100
    86. (~i) >> 5, int: 36625899, binary:
    87. 10001011101101110111101011
    88. i >>> 5, int: 97591828, binary:
    89. 101110100010010001000010100
    90. (~i) >>> 5, int: 36625899, binary:
    91. 10001011101101110111101011
    92. ...
    93. */

    程序末尾有两个方法:printBinaryInt() 和 printBinaryLong()。它们分别接受 int 类型和 long 类型的参数,然后输出其二进制格式,并附有说明文字。上面的示例不但演示了 int 和 long 的所有按位操作,还展示了 int 和 long 的最小值、最大值、正 1 值和负 1 值的二进制形式,这样你就可以了解它们大概的样子。注意最高位表示符号:0 表示正,1 表示负。可以参考上面示例中int部分的输出。
    数字的二进制表示形式被称为 “有符号的二进制补码”。