用0xff进行与运算,需要进一步说明。

8
在下面的代码片段中,考虑用注释等效替换第8行。
1. private static String ipToText(byte[] ip) {
2.  StringBuffer result = new StringBuffer();
3.
4.  for (int i = 0; i < ip.length; i++) {
5.      if (i > 0)
6.          result.append(".");
7.
8.      result.append(ip[i]); // compare with result.append(0xff & ip[i]);
9.  }
10.
11.     return result.toString();
12. }

.equals() 测试确认添加 0xff 不会改变任何内容。这个掩码被应用的原因是什么?


我不确定,但看起来是转换为无符号字节。 - andbi
4个回答

17
在Java中,byte 是一个介于-128和127之间的数字(有符号的,就像Java中的每个整数一样(除了char,如果你想计算它))。通过与0xff进行按位与运算,你强制将其转换为介于0和255之间的正整数int
这是因为Java将执行扩展转换为int,使用符号扩展,因此你会得到一个负的int而不是负的byte。使用0xff进行掩码处理只会留下低8位,从而使数字再次变为正数(也是你最初想要的结果)。
你可能没有注意到这种差异,因为你测试的byte[]中只有小于128的值。
小例子:
public class A {
    public static void main(String[] args) {
        int[] ip = new int[] {192, 168, 101, 23};
        byte[] ipb = new byte[4];
        for (int i =0; i < 4; i++) {
            ipb[i] = (byte)ip[i];
        }

        for (int i =0; i < 4; i++) {
            System.out.println("Byte: " + ipb[i] + ", And: " + (0xff & ipb[i]));
        }
    }
}

这会打印输出

Byte: -64, And: 192
Byte: -88, And: 168
Byte: 101, And: 101
Byte: 23, And: 23

展示了在 byte 中的内容与当其还是一个 int 时进入该字节的内容之间的差异,以及 & 操作的结果。


回复:“这是因为0xff的类型是int,因此字节也会被提升为int”:即使两个参数都是byte类型,类型提升到int也会发生;Java没有专门针对byte&运算符。(在没有&的版本中,类型提升到int将在重载解析期间发生,因为StringBuffer没有append(byte)方法。) - ruakh
确实,你说得对。显然,相关的部分是我们在任何情况下都会得到一个符号扩展的宽化到“int”,通过屏蔽低8位,我们可以强制它再次成为无符号字节 :) - Joey
"unsigned,就像Java中的每个整数一样" - 你是指有符号的吗? - Nabin Bhandari
1
@NabinBhandari:当然,谢谢。你也可以直接编辑的。 - Joey

3

由于您已经在这里使用字节数组,并且正在进行位运算,因此可以忽略Java如何将所有字节视为有符号的。毕竟,您现在正在处理位级别,而在位级别上不存在“有符号”或“无符号”值。

用所有1掩码一个8位值(一个字节)只是浪费循环,因为没有什么东西会被掩码。按位与将在比较的两个位都为true时返回一个位true,因此如果掩码包含所有1,则保证在AND操作后掩码值的所有位将保持不变。

考虑以下示例:

掩盖上半字节:
     0110 1010
AND 0000 1111 (0x0F)
  = 0000 1010
掩盖下半字节:
     0110 1010
AND 1111 0000 (0xF0)
  = 0110 0000
掩盖... 嗯,什么也不做:
     0110 1010
AND 1111 1111 (0xFF)
  = 0110 1010

当然,如果您在此处使用完整的int,您将获得其他人所说的结果:您将“强制”int成为等效的无符号字节。


1
在这个例子中,我不明白它会有什么区别。您正在使用一个字节进行与运算。按定义,一个字节有8位,而加法掩码关闭最后8位。所以你取了8的最后8位,这不会做任何事情。
如果您要与之进行and运算的内容比一个字节大,例如short或int等,则使用0xff进行and运算是有意义的。

糟糕,我承认,我误读了问题。我一直在想如何将其放回字节数组中,没有注意到它是要转换为文本。 - Jay

1

只有当存在负字节时,这才会有所不同。通常使用& 0xff将字节解释为无符号。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接