我们可以在Java中创建无符号字节

问题描述 投票:168回答:15

我试图转换无符号的有符号字节。问题是我收到的数据是无符号的,Java不支持无符号字节,因此当它读取数据时,它将其视为已签名。

我尝试通过以下我从Stack Overflow获得的解决方案来转换它。

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

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

java unsigned
15个回答
101
投票

我不确定我理解你的问题。

我只是尝试了这个并且对于字节-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不允许将244表示为byte值,就像C一样。要在Byte.MAX_VALUE(127)之上表示正整数,您必须使用其他整数类型,如shortintlong


0
投票

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

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

0
投票

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

int myInt = 144;

byte myByte = (byte) myInt;

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

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

输出:

myChar : 90

有关更多信息,请查看How to display a hex/byte value in Java


0
投票

你也可以:

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

并且它在右侧24位上再次移位,但填充前导零。结果是:

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

这是无符号表示,等于133。

如果你试图施放a = (int) a;那么会发生什么是它保持字节的2的补码表示并将其存储为int也作为2的补码:

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

这意味着:-123


-2
投票

根据Java的限制,在当前数据类型格式中几乎不可能使用无符号字节。您可以使用其他语言的其他库来实现您正在实现的内容,然后您可以使用JNI调用它们。


-2
投票

如果你想在Java中使用无符号字节,只需从你感兴趣的数字中减去256.它将产生一个负值的two's complement,这是无符号字节中所需的数字。

例:

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 brick时,你需要使用这些脏黑客。


-2
投票

是的,不是。我一直在挖掘这个问题。就像我明白这一点:

事实是java已经将整数-128到127整数。可以在java中使用unsigned来表示:

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

例如,如果您添加-12签名号码为无符号,则得到244.但是您可以在签名中再次使用该号码,它必须转回签名,它将再次为-12。

如果您尝试将244添加到java字节,您将获得outOfIndexException。

干杯..


183
投票

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

39
投票

Java语言不提供类似unsigned关键字的任何内容。根据语言规范的byte表示介于-128-127之间的值。例如,如果将byte强制转换为int,则Java会将第一位解释为符号并使用sign extension

话虽这么说,没有什么能阻止你将byte简单地视为8位并将这些位解释为0到255之间的值。请记住,你无法用别人的方法强制解释。如果方法接受byte,则该方法接受介于-128和127之间的值,除非另有明确说明。

为方便起见,这里有一些有用的转换/操作:

来自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));

34
投票

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

int anUnsignedByte = (int) aSignedByte & 0xff;

20
投票

我认为其他答案涵盖了内存表示以及如何处理这些内容取决于您计划如何使用它的上下文。我要补充说Java 8 added some support for dealing with unsigned types。在这种情况下,您可以使用Byte.toUnsignedInt

int unsignedInt = Byte.toUnsignedInt(myByte);

4
投票

旁注,如果你想打印出来,你可以说

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

1
投票

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

如果你的系统函数需要传递一个无符号字节,你可以传递一个带符号的字节,因为它会自动将其视为无符号字节。

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

但是,您不太可能遇到此问题,因为系统函数隐藏在类后面以实现跨平台兼容性,尽管某些java.io读取方法将未记录的字节作为int返回。

如果您希望看到这个工作,请尝试将签名字节写入文件并将其作为无符号字节读回。


0
投票

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

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

通常,您可以将字节用作无符号字节,只需简单或无翻译。这一切都取决于它的使用方式。您需要澄清您打算用它做什么。


0
投票

虽然看起来很烦人(来自C),但是Java没有在语言中包含无符号字节,因此简单的“b&0xFF”操作会产生(签名)字节b的无符号值(罕见)实际需要的情况。这些位实际上并没有改变 - 只是解释(只有在对值进行一些数学运算时才重要)。

© www.soinside.com 2019 - 2024. All rights reserved.