为什么Java对负字节的无符号位移位如此奇怪?
我有一个字节变量:为什么Java对负字节的无符号位移位如此奇怪?,java,bit-shift,primitive-types,Java,Bit Shift,Primitive Types,我有一个字节变量: byte varB = (byte) -1; // binary view: 1111 1111 我希望看到最左边的两个位,并执行6位的无符号右移: varB = (byte) (varB >>> 6); 但是我得到了-1,就好像它是int类型的一样,只有当我换30档时,我才能得到3 我如何解决这个问题,并仅通过6位移位获得结果?原因是位移位时,与数值提升到int相关的符号扩展。值varB在移位前提升为int。确实会发生无符号位向右移位,但当回退到字节时
byte varB = (byte) -1; // binary view: 1111 1111
我希望看到最左边的两个位,并执行6位的无符号右移:
varB = (byte) (varB >>> 6);
但是我得到了-1,就好像它是int类型的一样,只有当我换30档时,我才能得到3
我如何解决这个问题,并仅通过6位移位获得结果?原因是位移位时,与数值提升到
int
相关的符号扩展。值varB
在移位前提升为int
。确实会发生无符号位向右移位,但当回退到字节时,其效果会下降,这只会保留最后8位:
varB (byte) : 11111111
promoted to int : 11111111 11111111 11111111 11111111
shift right 6 : 00000011 11111111 11111111 11111111
cast to byte : 11111111
您可以使用按位and运算符&
在移位前屏蔽掉不需要的位。与0xFF
进行位和运算只保留8个最低有效位
varB = (byte) ((varB & 0xFF) >>> 6);
下面是现在发生的事情:
varB (byte) : 11111111
promoted to int : 11111111 11111111 11111111 11111111
bit-and mask : 00000000 00000000 00000000 11111111
shift right 6 : 00000000 00000000 00000000 00000011
cast to byte : 00000011
因为这就是java中字节移位在语言中的定义:
其要点是,小于int的类型被悄悄地扩展到int,移位,然后缩小到int
这使得您的单行线实际上相当于:
byte b = -1; // 1111_1111
int temp = b; // 1111_1111_1111_1111_1111_1111_1111_1111
temp >>>= 6; // 0000_0011_1111_1111_1111_1111_1111_1111
b = (byte) temp; // 1111_1111
要仅移动字节,您需要使用无符号语义显式地进行加宽转换(并且也需要手动进行加宽转换):
对char
、byte
或short
的所有算术运算首先升级到int
。“升级到int时”表示将byte转换为int:(int)varB
。虽然它们的值是相同的,但二进制文件变化很大。
byte b = -1; // 1111_1111
int temp = b & 0xFF; // 0000_0000_0000_0000_0000_0000_1111_1111
temp >>>= 6; // 0000_0000_0000_0000_0000_0000_0000_0011
b = (byte) temp; // 0000_0011