移位操作符(shift operator) 摘自Think In Java 3 chs

移位操作符(shift operator)
移位操作符操作的运算对象也是二进制的“位”,但是它们只可以被用来处理整数类型(基本类型的一种)。左移位操作符(<<)能将操作符左边的运算对象向左移动操作符右侧指定的位数(在低位补0)。“有符号”右移位操作符(>>)则将操作符左边的运算对象向右移动操作符右侧指定的位数。“有符号”右移位操作符使用了“符号扩展”:若符号为正,则在高位插入0;若符号为负,则在高位插入1。Java中增加了一种“无符号”右移位操作符(>>>),它使用了“零扩展”:无论正负,都在高位插入0。这一操作符是C或C++没有的。
如果对char、byte或者short类型的数值进行移位处理,那么在移位进行之前,它们会自动转换为int,并且得到的结果也是一个int类型的值。而右侧操作数,作为真正移位的位数,只有其二进制表示中的低5位才有用。这样可防止我们移位超过int型值所具有的位数。(译注:因为2的5次方为32,而int型值只有32位)。若对一个long类型的数值进行处理,最后得到的结果也是long。此时只会用到右侧操作数的低6位,以防止移位超过long型数值具有的位数。
移位可与等号(<<=或>>=或>>>=)组合使用。此时,操作符左边的值会移动由右边的值指定的位数,再将得到的结果赋回左边的变量。但在进行“无符号”右移结合赋值操作时,可能会遇到一个问题:如果对byte或short值进行这样的移位运算,得到的可能不是正确的结果。它们会先被转换成int类型,再进行右移操作。然后被截断,赋值给原来的类型,在这种情况下可能得到-1的结果。下面这个例子演示了这种情况:
//: c03:URShift.java
// Test of unsigned right shift.
import com.bruceeckel.simpletest.*;
public class URShift {
static Test monitor = new Test();
public static void main(String[] args) {
int i = -1;
System.out.println(i >>>= 10);
long l = -1;
System.out.println(l >>>= 10);
short s = -1;
System.out.println(s >>>= 10);//short(16b)和byte(8b)做移位操作时要转换为int(32b),为负值时高位补1,移位后截取低位的相应位数,
byte b = -1;
System.out.println(b >>>= 10);
b = -1;
System.out.println(b>>>10);
monitor.expect(new String[] {
"4194303",
"18014398509481983",
"-1",
"-1",
"4194303"
});
}
} ///:~
在最后一个移位运算中,结果没有赋回给b,而是直接打印出来,所以其结果是正确的。

改了一下例子,方便理解:

public class URShift {

public static void main(String[] args) {
int i = -1;
printBinaryInt("i",i);
printBinaryInt("i >>>= 10",i >>>= 10);
long l = -1;
printBinaryLong("l",l);
printBinaryLong("l >>>= 10",l >>>= 10);
short s = -1;
printBinaryShort("s",s);
printBinaryShort("s >>>= 17",s >>>= 17);
s = -1;
printBinaryShort("s",s);
printBinaryInt("s >>>17",s >>>17);
byte b = -1;
printBinaryByte("b",b);
printBinaryByte("b >>>= 25",b >>>= 25);
b = -1;
printBinaryByte("b",b);
printBinaryInt("b>>>25",b>>> 25);

}
static void printBinaryByte(String s, byte i) {
System.out.println(
s + ", byte: " + i + ", binary: ");
System.out.print(" ");
for(int j = 7; j >= 0; j--)
if(((1 << j) & i) != 0)
System.out.print("1");
else
System.out.print("0");
System.out.println();
}
static void printBinaryShort(String s, short i) {
System.out.println(
s + ", short: " + i + ", binary: ");
System.out.print(" ");
for(int j = 15; j >= 0; j--)
if(((1 << j) & i) != 0)
System.out.print("1");
else
System.out.print("0");
System.out.println();
}
static void printBinaryInt(String s, int i) {
System.out.println(
s + ", int: " + i + ", binary: ");
System.out.print(" ");
for(int j = 31; j >= 0; j--)
if(((1 << j) & i) != 0)
System.out.print("1");
else
System.out.print("0");
System.out.println();
}
static void printBinaryLong(String s, long l) {
System.out.println(
s + ", long: " + l + ", binary: ");
System.out.print(" ");
for(int i = 63; i >= 0; i--)
if(((1L << i) & l) != 0)
System.out.print("1");
else
System.out.print("0");
System.out.println();
}
}

相应输出:

i, int: -1, binary:
 11111111111111111111111111111111
i >>>= 10, int: 4194303, binary:
 00000000001111111111111111111111
l, long: -1, binary:
 1111111111111111111111111111111111111111111111111111111111111111
l >>>= 10, long: 18014398509481983, binary:
 0000000000111111111111111111111111111111111111111111111111111111
s, short: -1, binary:
 1111111111111111
s >>>= 17, short: 32767, binary:
 0111111111111111
s, short: -1, binary:
 1111111111111111
s >>>17, int: 32767, binary:
 00000000000000000111111111111111
b, byte: -1, binary:
 11111111
b >>>= 25, byte: 127, binary:
 01111111
b, byte: -1, binary:
 11111111
b>>>25, int: 127, binary:
 00000000000000000000000001111111

二进制位分析:

0000 0000 0000 0000 0000 0000 0000 0000

1111 1111 1111 1111 1111 1111 1111 1111
0000 0000 0011 1111 1111 1111 1111 1111 2^22-1

1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111
0000 0000 0011 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 2^54-1

1111 1111 1111 1111
1111 1111 1111 1111 1111 1111 1111 1111
0000 0000 0011 1111 1111 1111 1111 1111

1111 1111
1111 1111 1111 1111 1111 1111 1111 1111
0000 0000 0011 1111 1111 1111 1111 1111

 


下面这个例子向大家阐示了如何应用涉及“按位”操作的所有操作符:
//: c03:BitManipulation.java
// Using the bitwise operators.
import com.bruceeckel.simpletest.*;
import java.util.*;
public class BitManipulation {
static Test monitor = new Test();
public static void main(String[] args) {
Random rand = new Random();
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);
monitor.expect("BitManipulation.out");
}
static void printBinaryInt(String s, int i) {
System.out.println(
s + ", int: " + i + ", binary: ");
System.out.print(" ");
for(int j = 31; j >= 0; j--)
if(((1 << j) & i) != 0)
System.out.print("1");
else
System.out.print("0");
System.out.println();
}
static void printBinaryLong(String s, long l) {
System.out.println(
s + ", long: " + l + ", binary: ");
System.out.print(" ");
for(int i = 63; i >= 0; i--)
if(((1L << i) & l) != 0)
System.out.print("1");
else
System.out.print("0");
System.out.println();
}
} ///:~
程序末尾调用了两个方法:printBinaryInt()和printBinaryLong()。它们分别接受一个int或long值的参数,并用二进制格式输出,同时附有简要的说明文字。你可以暂时忽略它们具体是如何实现的。
请注意这里是用System.out.print(),而不是System.out.println()。print()方法不自动换行,所以我们能在同一行里输出多个信息。
上面的例子中,expect() 以一个文件名作参数,它会从这个文件中读取预期的行(其中可以有,也可以没有正则表达式)。对于那些太长,不适宜列在书里的输出,这种做法很有用。这个文件的扩展名是“.out”,是所发布的代码的一部分,可以从www.BruceEckel.com下载。如果有兴趣的话,可以打开这个文件,看看正确的输出应该是什么(或者你自己直接运行一下前面这个程序)。
上面的例子展示了对int和long的所有按位运算的效果,还展示了int和long的最小值、最大值、+1和-1值,以及它们的二进制形式,以使大家了解它们在机器中的具体形式。注意,最高位表示符号:0为正,1为负。下面列出例子中关于int部分的输出:
-1, int: -1, binary:
11111111111111111111111111111111
+1, int: 1, binary:
00000000000000000000000000000001
maxpos, int: 2147483647, binary:
01111111111111111111111111111111
maxneg, int: -2147483648, binary:
10000000000000000000000000000000
i, int: 59081716, binary:
00000011100001011000001111110100
~i, int: -59081717, binary:
11111100011110100111110000001011
-i, int: -59081716, binary:
11111100011110100111110000001100
j, int: 198850956, binary:
00001011110110100011100110001100
i & j, int: 58720644, binary:
00000011100000000000000110000100
i | j, int: 199212028, binary:
00001011110111111011101111111100
i ^ j, int: 140491384, binary:
00001000010111111011101001111000
i << 5, int: 1890614912, binary:
01110000101100000111111010000000
i >> 5, int: 1846303, binary:
00000000000111000010110000011111
(~i) >> 5, int: -1846304, binary:
11111111111000111101001111100000
i >>> 5, int: 1846303, binary:
00000000000111000010110000011111
(~i) >>> 5, int: 132371424, binary:
00000111111000111101001111100000
数字的二进制表示形式被称为“有符号的2的补码”。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值