• 移位操作符(shift operators)

   移位操作符同样是位的操作,有以下三种:

  1.    <<    (往左移位)

  2.    >>    (往右移位)

  3.    >>>   (无符号右移位)

下面对以上的三种移位操作做简单的说明

   “<<”将目标数向左移位,在低位补“0”。

   “>>”将目标数向右移位,此时应注意,“>>”使用符号延伸(sign extension),若目标数是正数(positive),在高位补“0”;若目标数是负数(negative),在高位补“1”。

   “>>>”使用“0”延伸(zero extension),不管目标数是正数还是负数,总是在高位补“0”。

注意:无符号右移位“>>>”在C/C++中是不存在的。

   如果执行移位操作的是 char 、byte、short型,在移位之前会先将其转化为 int 型,只有低5位会被操作(阻止在 int 型中更多的位被操作)。如果执行移位操作的是long 型,结果将会是long 型,只有低6位会被操作(所以你不能操作低6位之外的其它的位)。

   移位操作符可以和赋值操作符“=”结合使用(<<=、>>=、>>>=),但是这里有一个问题,当无符号右移位与赋值操作符结合使用时(即>>>=),如果操作的是byte 或是 short ,那么就会得不到正确的结果。实际上,这时,会先将 byte或是short 转化为int ,然后执行右移位的操作,最后将高位截去(truncated),将剩余的与byteshort长度相符的位赋值给左边原先定义好的变量。所以在这些情况下,你将会得到“-1”。下面的例子说明(demonstrates)了这一点。

  • 1-1 无符号右移位的例子

//: operators/URShift.java
// Test of unsigned right shift.
import static net.mindview.util.Print.*;
public class URShift {
  public static void main(String[] args) {
    int i = -1;
    print(Integer.toBinaryString(i));
    i >>>= 10;
    print(Integer.toBinaryString(i));
    long l = -1;
    print(Long.toBinaryString(l));
    l >>>= 10;
    print(Long.toBinaryString(l));
    short s = -1;
    print(Integer.toBinaryString(s));
    s >>>= 10;
    print(Integer.toBinaryString(s));
    byte b = -1;
    print(Integer.toBinaryString(b));
    b >>>= 10;
    print(Integer.toBinaryString(b));
    b = -1;
    print(Integer.toBinaryString(b));
    print(Integer.toBinaryString(b>>>10));
  }
}

程序运行的结果如下

155807789.png

说明

  1. 代码

    import static net.mindview.util.Print.*;

    是引入存放书中代码的 Print.java 文件,该文件只是处理输出的格式(使用代码之前应该先将类似“D:\TIJ4\code”的路径添加到“classpath”环境变量中,code文件下存放书中所有的代码,Print.java的代码将会在下面给出

  2. 代码

    print(Integer.toBinaryString(b>>>10));

    没有将移位操作的结果返回给b,而是直接打印出来,所以得到了正确的结果。

   下面的这个例子涉及到了所有的移位操作。

  • 1-2 所有移位操作的例子

//: operators/BitManipulation.java
// Using the bitwise operators.
import java.util.*;
import static net.mindview.util.Print.*;
public class BitManipulation {
  public static void main(String[] args) {
    Random rand = new Random(47);
    int i = rand.nextInt();
    int j = rand.nextInt();
    printBinaryInt("-1", -1);
    printBinaryInt("+1", +1);
    int maxpos = 2147483647;
    printBinaryInt("maxpos", maxpos);
    int maxneg = -2147483648;
    printBinaryInt("maxneg", maxneg);
    printBinaryInt("i", i);
    printBinaryInt("~i", ~i);
    printBinaryInt("-i", -i);
    printBinaryInt("j", j);
    printBinaryInt("i & j", i & j);
    printBinaryInt("i | j", i | j);
    printBinaryInt("i ^ j", i ^ j);
    printBinaryInt("i << 5", i << 5);
    printBinaryInt("i >> 5", i >> 5);
    printBinaryInt("(~i) >> 5", (~i) >> 5);
    printBinaryInt("i >>> 5", i >>> 5);
    printBinaryInt("(~i) >>> 5", (~i) >>> 5);
    long l = rand.nextLong();
    long m = rand.nextLong();
    printBinaryLong("-1L", -1L);
    printBinaryLong("+1L", +1L);
    long ll = 9223372036854775807L;
    printBinaryLong("maxpos", ll);
    long lln = -9223372036854775808L;
    printBinaryLong("maxneg", lln);
    printBinaryLong("l", l);
    printBinaryLong("~l", ~l);
    printBinaryLong("-l", -l);
    printBinaryLong("m", m);
    printBinaryLong("l & m", l & m);
    printBinaryLong("l | m", l | m);
    printBinaryLong("l ^ m", l ^ m);
    printBinaryLong("l << 5", l << 5);
    printBinaryLong("l >> 5", l >> 5);
    printBinaryLong("(~l) >> 5", (~l) >> 5);
    printBinaryLong("l >>> 5", l >>> 5);
    printBinaryLong("(~l) >>> 5", (~l) >>> 5);
  }
  static void printBinaryInt(String s, int i) {
    print(s + ", int: " + i + ", binary:\n   " +
      Integer.toBinaryString(i));
  }
  static void printBinaryLong(String s, long l) {
    print(s + ", long: " + l + ", binary:\n    " +
      Long.toBinaryString(l));
  }
}

程序运行的结果如下

171929193.png

171929149.png

  1. 从输出可以看出不同的类型对应的位数是不同的,int为32位,byte为8位,char和short是16位,long是64位。

  2. 高位代表符号,“0”表示正数,“1”表示负数

  • 1-3 Print.java的源代码

//: net/mindview/util/Print.java
// Print methods that can be used without
// qualifiers, using Java SE5 static imports:
package net.mindview.util;
import java.io.*;
public class Print {
  // Print with a newline:
  public static void print(Object obj) {
    System.out.println(obj);
  }
  // Print a newline by itself:
  public static void print() {
    System.out.println();
  }
  // Print with no line break:
  public static void printnb(Object obj) {
    System.out.print(obj);
  }
  // The new Java SE5 printf() (from C):
  public static PrintStream
  printf(String format, Object... args) {
    return System.out.printf(format, args);
  }
}

注:文章的代码摘自 Thinking in Java(Fourth Edition)英文版,作者 [美]Bruce Eckef,刘中兵 评注。