我们可以在Java中制作无符号字节吗

发布于 2024-10-04 03:46:27 字数 325 浏览 5 评论 0原文

我正在尝试将有符号字节转换为无符号字节。问题是我收到的数据是无符号的,而Java不支持无符号字节,因此当它读取数据时,它会将其视为有符号的。

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

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

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

I am trying to convert a signed byte in unsigned. The problem is the data I am receiving is unsigned and Java does not support unsigned byte, so when it reads the data it treats it as signed.

I tried it to convert it by the following solution I got from Stack Overflow.

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

But when again it's converted in byte, I get the same signed data. I am trying to use this data as a parameter to a function of Java that accepts only a byte as parameter, so I can't use any other data type. How can I fix this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(17

淡看悲欢离合 2024-10-11 03:46:27

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

由于原语已签名,Java 编译器将阻止您将高于 +127 的值分配给字节(或低于 -128)。但是,没有什么可以阻止您向下转换 int (或短整型)以实现此目的:

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

The fact that primitives are signed in Java is irrelevant to how they're represented in memory / transit - a byte is merely 8 bits and whether you interpret that as a signed range or not is up to you. There is no magic flag to say "this is signed" or "this is unsigned".

As primitives are signed the Java compiler will prevent you from assigning a value higher than +127 to a byte (or lower than -128). However, there's nothing to stop you downcasting an int (or short) in order to achieve this:

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"
}
最冷一天 2024-10-11 03:46:27

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

我刚刚尝试过,对于字节 -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

I'm not sure I understand your question.

I just tried this and for byte -12 (signed value) it returned integer 244 (equivalent to unsigned byte value but typed as an int):

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

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

Is it what you want to do?

Java does not allow to express 244 as a byte value, as would C. To express positive integers above Byte.MAX_VALUE (127) you have to use a different integral type, like short, int or long.

孤凫 2024-10-11 03:46:27

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

话虽如此,没有什么可以阻止您将 byte 简单地视为 8 位,并将这些位解释为 0 到 255 之间的值。请记住,您无法将您的解释强加于他人别人的方法。如果一个方法接受字节,则该方法接受 -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));

The Java Language does not provide anything like the unsigned keyword. A byte according to the language spec represents a value between −128 - 127. For instance, if a byte is cast to an int Java will interpret the first bit as the sign and use sign extension.

That being said, nothing prevents you from viewing a byte simply as 8 bits and interpret those bits as a value between 0 and 255. Just keep in mind that there's nothing you can do to force your interpretation upon someone else's method. If a method accepts a byte, then that method accepts a value between −128 and 127 unless explicitly stated otherwise.

Here are a couple of useful conversions / manipulations for your convenience:

Conversions to / from 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

(Or, if you're on Java 8+, use Byte.toUnsignedInt.)

Parsing / formatting

Best way is to use the above conversions:

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

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

Arithmetics

The 2-complement representation "just works" for addition, subtraction and multiplication:

// 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

Division requires manual conversion of operands:

byte ratio = (byte) ((b1 & 0xFF) / (b2 & 0xFF));
一萌ing 2024-10-11 03:46:27

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

int anUnsignedByte = (int) aSignedByte & 0xff;

There are no primitive unsigned bytes in Java. The usual thing is to cast it to bigger type:

int anUnsignedByte = (int) aSignedByte & 0xff;
扬花落满肩 2024-10-11 03:46:27

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

int unsignedInt = Byte.toUnsignedInt(myByte);

I think the other answers have covered memory representation and how you handle these depends on the context of how you plan on using it. I'll add that Java 8 added some support for dealing with unsigned types. In this case, you could use Byte.toUnsignedInt

int unsignedInt = Byte.toUnsignedInt(myByte);
段念尘 2024-10-11 03:46:27

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

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

A side note, if you want to print it out, you can just say

byte b = 255;
System.out.println((b < 0 ? 256 + b : b));
-残月青衣踏尘吟 2024-10-11 03:46:27

您还可以:

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

解释:

假设a = (byte) 133;

在内存中它存储为:“1000 0101”(十六进制为0x85)

因此它的表示翻译 >无符号=133,有符号=-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

You can also:

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

Explanation:

let's say a = (byte) 133;

In memory it's stored as: "1000 0101" (0x85 in hex)

So its representation translates unsigned=133, signed=-123 (as 2's complement)

a << 24

When left shift is performed 24 bits to the left, the result is now a 4 byte integer which is represented as:

"10000101 00000000 00000000 00000000" (or "0x85000000" in hex)

then we have

( a << 24) >>> 24

and it shifts again on the right 24 bits but fills with leading zeros. So it results to:

"00000000 00000000 00000000 10000101" (or "0x00000085" in hex)

and that is the unsigned representation which equals to 133.

If you tried to cast a = (int) a;
then what would happen is it keeps the 2's complement representation of byte and stores it as int also as 2's complement:

(int) "10000101" ---> "11111111 11111111 11111111 10000101"

And that translates as: -123

还给你自由 2024-10-11 03:46:27

尽管Java在语言中不包含无符号字节可能看起来很烦人(来自C),但这实际上没什么大不了的,因为简单的“b&amp; 0xFF”操作会在(罕见的)中产生(有符号)字节b的无符号值。 )实际需要的情况。这些位实际上并没有改变——只是解释(这仅在对值进行一些数学运算时才重要)。

Although it may seem annoying (coming from C) that Java did not include unsigned byte in the language it really is no big deal since a simple "b & 0xFF" operation yields the unsigned value for (signed) byte b in the (rare) situations that it is actually needed. The bits don't actually change -- just the interpretation (which is important only when doing for example some math operations on the values).

层林尽染 2024-10-11 03:46:27

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

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

If think you are looking for something like this.

public static char toUnsigned(byte b) {
    return (char) (b >= 0 ? b : 256 + b);
}
黑凤梨 2024-10-11 03:46:27

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

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

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

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

如果您想查看此操作,请尝试将有符号字节写入文件并将它们作为无符号字节读回。

Adamski provided the best answer, but it is not quite complete, so read his reply, as it explains the details I'm not.

If you have a system function that requires an unsigned byte to be passed to it, you can pass a signed byte as it will automatically treat it as an unsigned byte.

So if a system function requires four bytes, for example, 192 168 0 1 as unsigned bytes you can pass -64 -88 0 1, and the function will still work, because the act of passing them to the function will un-sign them.

However you are unlikely to have this problem as system functions are hidden behind classes for cross-platform compatibility, though some of the java.io read methods return unsighed bytes as an int.

If you want to see this working, try writing signed bytes to a file and read them back as unsigned bytes.

初懵 2024-10-11 03:46:27

我正在尝试将此数据用作仅接受字节作为参数的 Java 函数的参数

这与接受要向其传递大于 2^32-1 的值的整数的函数没有太大区别。

听起来这取决于函数的定义和记录方式;我可以看到三种可能性:

  1. 它可能明确记录该函数将字节视为无符号值,在这种情况下,该函数可能应该执行您期望的操作,但似乎实现错误。对于整数情况,函数可能会将参数声明为无符号整数,但对于字节情况则不可能。

  2. 它可能记录该参数的值必须大于(或可能等于)零,在这种情况下,您滥用该函数(传递超出范围的参数),期望它做的事情比它多被设计来做。通过某种程度的调试支持,您可能期望该函数抛出异常或断言失败。

  3. 文档可能什么也没说,在这种情况下,负参数就是负参数,它是否具有任何意义取决于函数的作用。如果这没有意义,那么也许该函数实际上应该被定义/记录为 (2)。如果这以一种不明显的方式有意义(例如,非负值用于索引到数组,负值用于从数组末尾索引,所以 -1 表示最后一个元素),文档应该说明它是什么意味着,我希望这不是你想要它做的事情。

I am trying to use this data as a parameter to a function of Java that accepts only a byte as parameter

This is not substantially different from a function accepting an integer to which you want to pass a value larger than 2^32-1.

That sounds like it depends on how the function is defined and documented; I can see three possibilities:

  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.

  2. 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.

  3. 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.

初懵 2024-10-11 03:46:27

在想了解 netty ByteBuf writeInt 和 readUnsignedInt 方法的明显不对称性后,我碰巧意外地登陆了此页面。

在阅读了有趣且有教育意义的答案后,我仍然想知道当您说时您正在调用什么函数:

我正在尝试使用此数据作为 Java 函数的参数
仅接受一个字节作为参数。

对于这么多年后它的价值,这是我的五十美分:

让我们假设您正在调用的方法正在用微量更新一些余额,并且它的行为根据一些明确定义的要求集。即,它被认为对其预期行为有正确的实现:

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

基本上,如果您提供正数,它将被添加到余额中,而负数将从余额中有效地减去。现在,因为它接受一个字节作为其参数,所以隐含的假设是它在功能上仅接受 -128 和 +127 之间的金额。因此,如果您想使用此方法将 130 添加到余额中,它根本不会产生您想要的结果,因为在该方法的实现中无法表示高于 127 的金额。因此通过它130 不会得到你想要的结果
行为。请注意,该方法无法实现(例如)AmountOutOfBoundsException,因为 130 将被“解释”为仍然遵守该方法约定的负值。

所以我有以下问题:

  • 您是否根据其(隐式或显式)合同使用该方法?
  • 该方法实施是否正确?
  • 我仍然误解你的问题吗?

I happened to accidentally land on this page after wondering about the apparent asymmetry of the netty ByteBuf writeInt and readUnsignedInt methods.

After reading the interesting and educational answers I am still wondering what function you were calling when you said:

I am trying to use this data as a parameter to a function of Java that
accepts only a byte as parameter.

For what it's worth after so many years, here is my fifty cents:

Let's assume the method you are calling is updating some balance with micro amounts and that it behaves according to some well-defined set of requirements. Ie, it is considered to have a correct implementation for its intended behavior:

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.

So I have the following questions:

  • are you using the method according to its (implicit or explicit) contract?
  • is the method implemented correctly?
  • am I still misunderstanding your question?
走走停停 2024-10-11 03:46:27

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

int myInt = 144;

byte myByte = (byte) myInt;

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

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

Output:

myChar : 90

For more information, please check, 如何在 Java 中显示十六进制/字节值

There is no unsigned byte in Java, but if you want to display a byte, you can do,

int myInt = 144;

byte myByte = (byte) myInt;

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

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

Output:

myChar : 90

For more information, please check, How to display a hex/byte value in Java.

时光无声 2024-10-11 03:46:27

是和不是。我一直在研究这个问题。
就像我理解的那样:

事实是java已经签署了整数-128到127..
可以在 java 中表示无符号数:

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

例如,如果添加 -12 有符号数为无符号数,则得到 244。但是您可以在有符号数中再次使用该数,必须将其移回有符号数,并且它将是再次-12。

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

干杯..

Yes and no. Ive been digging around with this problem.
Like i understand this:

The fact is that java has signed interger -128 to 127..
It is possible to present a unsigned in java with:

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

If you for example add -12 signed number to be unsigned you get 244. But you can use that number again in signed, it has to be shifted back to signed and it´ll be again -12.

If you try to add 244 to java byte you'll get outOfIndexException.

Cheers..

情栀口红 2024-10-11 03:46:27

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

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

通常,您可以将字节用作无符号字节,只需进行简单的转换或无需转换。这完全取决于它的使用方式。您需要澄清您打算用它做什么。

If you have a function which must be passed a signed byte, what do you expect it to do if you pass an unsigned byte?

Why can't you use any other data type?

Unsually you can use a byte as an unsigned byte with simple or no translations. It all depends on how it is used. You would need to clarify what you indend to do with it.

谈下烟灰 2024-10-11 03:46:27

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

As per limitations in Java, unsigned byte is almost impossible in the current data-type format. You can go for some other libraries of another language for what you are implementing and then you can call them using JNI.

汹涌人海 2024-10-11 03:46:27

如果你想要 Java 中的无符号字节,只需从你感兴趣的数字中减去 256 即可。它将产生 带有负值的二进制补码,这是所需的无符号字节数。

示例:

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.

当使用 leJOSNXT 砖

If you want unsigned bytes in Java, just subtract 256 from the number you're interested in. It will produce two's complement with a negative value, which is the desired number in unsigned bytes.

Example:

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.

You need to use such dirty hacks when using leJOS to program the NXT brick.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文