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

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

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

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


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

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

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


在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"
}

在Java中使用unsigned字节的完整指南:

Java中的无符号字节

(答案来源)


Java语言不提供任何类似unsigned关键字的东西。根据语言规范,一个字节表示−128 - 127之间的值。例如,如果将一个字节转换为int类型,Java将把第一位解释为符号并使用符号扩展。

也就是说,没有什么可以阻止您将一个字节简单地视为8位,并将这些位解释为0到255之间的值。只要记住,你不能把你的解释强加给别人的方法。如果一个方法接受一个字节,那么该方法接受−128到127之间的值,除非另有明确说明。

下面是一些有用的转换/操作,方便您使用:

从int到int的转换

// From int to unsigned byte
int i = 200;                    // some value between 0 and 255
byte b = (byte) i;              // 8 bits representing that value

// From unsigned byte to int
byte b = 123;                   // 8 bits representing a value between 0 and 255
int i = b & 0xFF;               // an int representing the same value

(或者,如果你使用的是Java 8+,使用Byte.toUnsignedInt。)

解析/格式化

最好的方法是使用上面的转换:

// Parse an unsigned byte
byte b = (byte) Integer.parseInt("200");

// Print an unsigned byte
System.out.println("Value of my unsigned byte: " + (b & 0xFF));

算法

2补表示“只适用于”加法、减法和乘法:

// two unsigned bytes
byte b1 = (byte) 200;
byte b2 = (byte) 15;

byte sum  = (byte) (b1 + b2);  // 215
byte diff = (byte) (b1 - b2);  // 185
byte prod = (byte) (b2 * b2);  // 225

除法需要手动转换操作数:

byte ratio = (byte) ((b1 & 0xFF) / (b2 & 0xFF));

我不太明白你的问题。

我刚刚尝试了这一点,对于字节-12(有符号值),它返回整数244(相当于无符号字节值,但类型为int):

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

  public static void main(String[] args) {
    System.out.println(unsignedToBytes((byte) -12));
  }

这是你想做的吗?

Java不允许像c那样将244表示为字节值。MAX_VALUE(127)你必须使用不同的整型,如short, int或long。


在Java中没有原始无符号字节。通常的做法是将其转换为更大的类型:

int anUnsignedByte = (int) aSignedByte & 0xff;

由于Java中的限制,无符号字节在当前的数据类型格式中几乎是不可能的。你可以为你要实现的东西使用其他语言的其他库,然后你可以使用JNI调用它们。


顺便说一句,如果你想打印出来,你可以说

byte b = 255;
System.out.println((b < 0 ? 256 + b : b));

如果您想在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产生无符号值。比特实际上并没有改变——只是解释(这只在例如对值进行一些数学运算时很重要)。


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

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

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

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

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


如果你认为你正在寻找这样的东西。

public static char toUnsigned(byte b) {
    return (char) (b >= 0 ? b : 256 + b);
}

在Java中没有无符号字节,但是如果你想显示一个字节,你可以这样做,

int myInt = 144;

byte myByte = (byte) myInt;

char myChar = (char) (myByte & 0xFF);

System.out.println("myChar :" + Integer.toHexString(myChar));

输出:

myChar : 90

有关更多信息,请查看如何在Java中显示十六进制/字节值。


我认为其他答案已经涵盖了内存表示,您如何处理这些取决于您计划如何使用它的上下文。我要补充的是,Java 8增加了一些处理无符号类型的支持。在这种情况下,您可以使用Byte.toUnsignedInt

int unsignedInt = Byte.toUnsignedInt(myByte);

是也不是。我一直在研究这个问题。 就像我明白这个

事实上,java已经对整数-128到127进行了签名。 在java中可以通过以下方式来表示unsigned对象:

public static int toUnsignedInt(byte x) {
    return ((int) x) & 0xff;
}

如果你把-12有符号数加为无符号数,就得到244。但是你可以再次使用这个数字,它必须被移回符号,它还是-12。

如果你尝试添加244到java字节,你会得到outOfIndexException。

欢呼声……


你还可以:

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函数,只接受一个字节作为参数

这与函数接受一个大于2^32-1的整数并没有本质上的区别。

这听起来似乎取决于函数是如何定义和记录的;我认为有三种可能:

It may explicitly document that the function treats the byte as an unsigned value, in which case the function probably should do what you expect but would seem to be implemented wrong. For the integer case, the function would probably declare the parameter as an unsigned integer, but that is not possible for the byte case. It may document that the value for this argument must be greater than (or perhaps equal to) zero, in which case you are misusing the function (passing an out-of-range parameter), expecting it to do more than it was designed to do. With some level of debugging support you might expect the function to throw an exception or fail an assertion. The documentation may say nothing, in which case a negative parameter is, well, a negative parameter and whether that has any meaning depends on what the function does. If this is meaningless then perhaps the function should really be defined/documented as (2). If this is meaningful in an nonobvious manner (e.g. non-negative values are used to index into an array, and negative values are used to index back from the end of the array so -1 means the last element) the documentation should say what it means and I would expect that it isn't what you want it to do anyway.


在好奇netty ByteBuf writeInt和readUnsignedInt方法的明显不对称之后,我碰巧偶然地进入了这个页面。

在阅读了有趣和有教育意义的答案后,我仍然想知道你说的时候调用的是什么函数:

我试图使用这些数据作为参数的Java函数 只接受一个字节作为参数。

不管这么多年过去了,我的50美分如下:

让我们假设您正在调用的方法正在用微量更新一些余额,并且它根据一些定义良好的需求集进行操作。也就是说,它被认为对其预期的行为有正确的实现:

long processMicroPayment(byte amount) {
    this.balance += amount;
    return balance;     
}

Basically, if you supply a positive amount it will be added to the balance, and a negative amount will effectively be subtracted from the balance. Now because it accepts a byte as its parameter the implicit assumption is that it functionally only accepts amounts between -128 and +127. So if you want to use this method to add, say, 130 to the balance, it simply will not produce the result YOU desire, because there is no way within the implementation of this method to represent an amount higher than 127. So passing it 130 will not result in your desired behavior. Note that the method has no way of implementing a (say) AmountOutOfBoundsException because 130 will be 'interpreted' as a negative value that is still obeying the method's contract.

我有以下几个问题:

您是否根据其(隐式或显式)契约使用该方法? 方法是否正确实现? 我还是误解了你的问题吗?