为什么位或操作会导致符号扩展但是不会?

时间:2013-11-29 03:52:19

标签: java bit-manipulation

我需要在Java中将一个字节转换为int,但我不希望使用符号扩展,所以我做了

byte b = -1
(int) (b & 0xF) // this returns 15, which is what I want
(int) (b | 0)   // this returns -1, which is essentially 0xFFFF, sign extension happens, not what I want

我认为上面两个应该给出相同的结果,但结果却并非如此。 我必须在比特操作中遗漏一些东西。

2 个答案:

答案 0 :(得分:2)

诀窍是打印这些值的二进制表示并对它们执行二进制操作

byte b = -1;
int a = (int) (b & 0xF); // this returns 15, which is what I want
int c = (int) (b | 0); // this returns -1, which is essentially 0xFFFF
System.out.println("b:" + Integer.toBinaryString(b));
System.out.println("a:" + Integer.toBinaryString(a));
System.out.println("c:" + Integer.toBinaryString(c));
System.out.println("0xF:" + Integer.toBinaryString(0xF));

打印

b:11111111111111111111111111111111
a:1111
c:11111111111111111111111111111111
0xF:1111

所以b & OxF

11111111111111111111111111111111
00000000000000000000000000001111  (AND)
--------------------------------
                            1111   (15)

b | 0

11111111111111111111111111111111
00000000000000000000000000000000   (OR)
--------------------------------
11111111111111111111111111111111   (-1)

Hot Licks explains why the byte value -1 is represented in binary as it is.

答案 1 :(得分:1)

这里的问题是按位运算符处理整数或长整数,而不是字节。 b & 0xF基本上被视为((int)b) & ((int)0xF)。您可以从每个操作的JLS定义中跟踪所有操作。

  • 第一个JLS 15.22.1(定义{{​​1}}和&)解释了当两个操作数都可以转换为整数基元类型时,“首先对操作数执行二进制数字提升(§5.6。 2)。“
  • 反过来说,
  • JLS 5.6.2表示除非操作数是|floatdouble,否则这两个值都会扩展为long
  • 最后,在JLS 5.1.2中定义了扩展,并指出“将有符号整数值的扩展转换为整数类型T只是对整数值的二进制补码表示进行符号扩展,以填充更宽的格式。”字节已签名(JLS 4.2)。

因此,在使用右操作数进行“与”或“或”运算之前,您的int字节使用符号扩展名扩展为b

请注意,这意味着int的结果应该是b & 0F,而不是int。事实上就是这种情况(意味着你明确地将它转发给byte是多余的)。您可以通过将其自动装箱到int然后检查该对象的类型来测试:

Object