Java - &0xff 将 8 到 31 的位设为 1

问题描述

我在使用 0xff 执行 AND 运算符时遇到问题。

public Pixel(int x,int y,int p) {
    this.x = x;
    this.y = y;
    pixelValue = p;
    A = (byte) ((p>>24) & 0xff);
    R = (byte) ((p>>16) & 0xff);
    R = (byte) (R&0xff);
    G = (byte) ((p>>8) & 0xff);
    B =(byte) (p & 0xff);
    printAll();
}
void printAll() {
    System.out.println("A "+Integer.toBinaryString(A));
    System.out.println(Byte.toUnsignedInt(A));
    System.out.println("R "+Integer.toBinaryString(R));
    System.out.println(Byte.toUnsignedInt(R));
    System.out.println("G "+Integer.toBinaryString(G));
    System.out.println(Byte.toUnsignedInt(G));
    System.out.println("B "+Integer.toBinaryString(B));
    System.out.println(Byte.toUnsignedInt(B));
    System.out.println("pixelValue"+pixelValue);
    System.out.println(Integer.toBinaryString((byte)(pixelValue)));
}

在执行 Pixel p = new Pixel(0,2145687240); 时 我得到

A 1111111
127
R 11111111111111111111111111100100
228
G 11111111111111111111111110010110
150
B 11111111111111111111111111001000
200
pixelValue-56
11111111111111111111111111001000

问题是,为什么 R、G 和 B 都填充了 1?为什么A只有7位? 为什么在调用 &0xff 时我得到 11111111111111111111111111100100?这不应该取消前 8 个字节以外的所有内容吗?

解决方法

字节从 0255(含),因为它们可以容纳 2^8=256 值。至少那是未签名的定义。

这里要问自己的问题是:如何表示负数?典型的方法是使用称为二进制补码的东西。第一位,不是像通常那样在关闭时表示 0 和在打开时表示 2^(n-1),而是在关闭时表示 0 和打开时表示 -2^(n-1)

因此,228 在内部存储为 11100100。如果您将其从基数 2 转换,您将看到这等于 228... 但仅当未签名时。

签名后,最后 7 位代表 100。然后,第一位,而不是代表128,而是代表-128。因此,签名时值为 -28

那么,当把它转换成整数时,由于一个整数有32位,那么第一位将表示-2147483648,因此最后31位将需要表示28 + 2147483648,即1111111111111111111111111100100 来自。因此,-28 的 32 位表示是 11111111111111111111111111100100

如果您真的想拥有 228,您可能希望对 Integer.toBinaryString 的结果调用 Byte.toUnsignedInt,顾名思义,它会将其转换为 无符号 号码。这里的问题是它正在签名,这意味着它是-28,而不是您想要的228