Java 移位奇怪

标签 java debugging bit-shift

Java 有 2 个用于右移的移位运算符:

>> shifts right, and is dependant on the sign bit for the sign of the result

>>> shifts right and shifts a zero into leftmost bits

http://java.sun.com/docs/books/tutorial/java/nutsandbolts/op3.html

这看起来相当简单,所以任何人都可以向我解释为什么这段代码在给 bar 赋值 -128 时为 foo 生成 -2 的值:

byte foo = (byte)((bar & ((byte)-64)) >>> 6);

这样做的目的是获取一个 8 位字节,最左边 2 位的掩码,并将它们移到最右边的 2 位。即:

initial = 0b10000000 (-128)
-64 = 0b11000000
initial & -64 = 0b10000000
0b10000000 >>> 6 = 0b00000010

结果实际上是-2,也就是

0b11111110

即。 1 而不是零被移到左边的位置

最佳答案

这是因为 & 实际上正在执行对 int 的提升 - 这留下了非常多的“1”位。然后向右移动,将最左边的 2 位保留为 0,但随后通过转换回字节忽略那些最左边的位。

当您分离操作时,这会变得更清楚:

public class Test
{
    public static void main(String[] args)
    {
        byte bar = -128;
        int tmp = (bar & ((byte)-64)) >>> 6;
        byte foo = (byte)tmp;
        System.out.println(tmp);
        System.out.println(foo);
    }
}

打印

67108862
-2

所以再次进行位运算:

initial = 0b10000000 (-128)
-64 = 0b11000000
initial & -64 = 0b11111111111111111111111110000000 // it's an int now
0b10000000 >>> 6 = 0b00111111111111111111111111100000 // note zero-padding
(byte) (0b10000000 >>> 6) = 11100000 // -2

即使您从 & 操作中得到正确的结果(通过在该点进行强制转换),>>> 无论如何都会首先将第一个操作数提升为 int

编辑:解决方案是改变你掩盖事物的方式。不是用 -64 掩码,而是用 128+64=192=0xc0 掩码:

byte foo = (byte)((bar & 0xc0) >>> 6);

这样您实际上只剩下您想要的两位,而不是在最高有效的 24 位中加载 1。

关于Java 移位奇怪,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2173205/

相关文章:

此处应为 Java Servlet 接口(interface)

Java BigInteger 和 Shift 运算符

delphi - 如何从 shl 获得大于 2^32 的结果?

Node.JS 错误代码的含义? (特别是FS)

bit-manipulation - 为一系列位创建位掩码的最佳实践方法是什么?

java - 从 Google Cloud 端点返回多态对象

java - SimpleDateFormat() 在传递无效日期格式时不会给出 IllegalArgumentException

java - 如何在android应用程序中实现在adobe pdf reader中构建

delphi - 调试器中出现奇怪的 "inaccessible value"

c++ - LLDB 中的重复命令