我试图转换一个无符号的有符号字节。问题是我接收的数据是无符号的,Java不支持无符号字节,所以当它读取数据时,它将其视为有符号的。

我尝试通过下面的解决方案转换它,我从Stack Overflow。

public static int unsignedToBytes(byte a)
{
    int b = a & 0xFF;
    return b;
}

但是当它再次以字节为单位转换时,我得到了相同的带符号数据。我试图使用此数据作为参数的Java函数,只接受一个字节作为参数,所以我不能使用任何其他数据类型。我该如何解决这个问题?


当前回答

你还可以:

public static int unsignedToBytes(byte a)
{
    return (int) ( ( a << 24) >>> 24);
}    

解释:

假设a = (byte) 133;

在内存中,它被存储为:"1000 0101"(十六进制中的0x85)

所以它的表示可以转换为unsigned=133, signed=-123(作为2的补码)

A << 24

当向左移动24位时,结果现在是一个4字节的整数,表示为:

"10000101 00000000 00000000 00000000"(或十六进制中的"0x85000000")

然后我们有

(a << 24) >>>

它又向右移动了24位,但前导都是0。结果是:

"00000000 00000000 00000000 10000101"(或十六进制中的"0x00000085")

这就是无符号表达式它等于133。

如果你试图强制转换a = (int) a; 然后会发生的是,它保留了字节的2补表示,并将其存储为int,同时也存储为2的补:

(int)“10000101”——>“11111111 11111111 11111111 10000101”

翻译过来就是-123

其他回答

如果你有一个函数必须传递一个有符号字节,如果你传递一个无符号字节,你期望它做什么?

为什么不能使用其他数据类型?

通常情况下,您可以使用一个字节作为一个无符号字节简单或不翻译。这完全取决于如何使用。你需要澄清你打算用它做什么。

如果您想在Java中使用无符号字节,只需从感兴趣的数字中减去256。它将生成带有负值的2的补数,这是所需的无符号字节数。

例子:

int speed = 255; //Integer with the desired byte value
byte speed_unsigned = (byte)(speed-256);
//This will be represented in two's complement so its binary value will be 1111 1111
//which is the unsigned byte we desire.

在使用leJOS编程NXT块时,您需要使用这种肮脏的技巧。

虽然Java语言中没有包含无符号字节看起来很烦人(来自C),但这真的不是什么大问题,因为一个简单的“b & 0xFF”操作在(很少)实际需要的情况下为(有符号)字节b产生无符号值。比特实际上并没有改变——只是解释(这只在例如对值进行一些数学运算时很重要)。

在Java中,原语是有符号的,这与它们在内存/传输中的表示方式无关——一个字节只有8位,是否将其解释为有符号范围取决于您。没有神奇的旗帜说“这是有符号的”或“这是没有符号的”。

由于原语是有符号的,Java编译器将阻止您为字节分配大于+127的值(或小于-128的值)。然而,没有什么可以阻止你向下转换一个int型(或short型)来实现这一点:

int i = 200; // 0000 0000 0000 0000 0000 0000 1100 1000 (200)
byte b = (byte) 200; // 1100 1000 (-56 by Java specification, 200 by convention)

/*
 * Will print a negative int -56 because upcasting byte to int does
 * so called "sign extension" which yields those bits:
 * 1111 1111 1111 1111 1111 1111 1100 1000 (-56)
 *
 * But you could still choose to interpret this as +200.
 */
System.out.println(b); // "-56"

/*
 * Will print a positive int 200 because bitwise AND with 0xFF will
 * zero all the 24 most significant bits that:
 * a) were added during upcasting to int which took place silently
 *    just before evaluating the bitwise AND operator.
 *    So the `b & 0xFF` is equivalent with `((int) b) & 0xFF`.
 * b) were set to 1s because of "sign extension" during the upcasting
 *
 * 1111 1111 1111 1111 1111 1111 1100 1000 (the int)
 * &
 * 0000 0000 0000 0000 0000 0000 1111 1111 (the 0xFF)
 * =======================================
 * 0000 0000 0000 0000 0000 0000 1100 1000 (200)
 */
System.out.println(b & 0xFF); // "200"

/*
 * You would typically do this *within* the method that expected an 
 * unsigned byte and the advantage is you apply `0xFF` only once
 * and than you use the `unsignedByte` variable in all your bitwise
 * operations.
 *
 * You could use any integer type longer than `byte` for the `unsignedByte` variable,
 * i.e. `short`, `int`, `long` and even `char`, but during bitwise operations
 * it would get casted to `int` anyway.
 */
void printUnsignedByte(byte b) {
    int unsignedByte = b & 0xFF;
    System.out.println(unsignedByte); // "200"
}

Adamski提供了最好的答案,但它并不完整,所以阅读他的回复,因为它解释了我没有的细节。

如果你有一个系统函数需要传递一个无符号字节给它,你可以传递一个有符号字节,因为它会自动把它当作一个无符号字节。

因此,如果一个系统函数需要四个字节,例如,192 168 0 1作为无符号字节,您可以传递-64 -88 0 1,并且函数仍然可以工作,因为将它们传递给函数的行为将取消它们的符号。

然而,您不太可能遇到这个问题,因为系统函数隐藏在类后面以实现跨平台兼容性,尽管一些java。IO read方法返回一个int类型的未叹号字节。

如果您希望看到这种工作,请尝试将有符号字节写入文件,并将它们作为无符号字节读取回来。