如何将Int转换为无符号字节并返回


92

我需要将数字转换为无符号字节。该数字始终小于或等于255,因此它将适合一个字节。

我还需要将该字节转换回该数字。我将如何用Java做到这一点?我尝试了几种方法,但均无效果。这是我现在想要做的:

int size = 5;
// Convert size int to binary
String sizeStr = Integer.toString(size);
byte binaryByte = Byte.valueOf(sizeStr);

现在将该字节转换回数字:

Byte test = new Byte(binaryByte);
int msgSize = test.intValue();

显然,这是行不通的。由于某种原因,它总是将数字转换为65。有什么建议?


我也尝试过这种方法:crazysquirrel.com/computing/java/basics/…-不起作用。
darksky 2011年

Answers:


200

字节始终用Java签名。不过,您可以通过将二进制与0xFF相乘来获得其无符号值:

int i = 234;
byte b = (byte) i;
System.out.println(b); // -22
int i2 = b & 0xFF;
System.out.println(i2); // 234

我仍然65岁...为什么呢?
darksky 2011年

1
它会将所需的数字存储在字节中。Java只是将其视为一个带符号的数字,而不是一个无符号的数字。但是每一位都和无符号数字一样。将字符串转换为字节是另一个不相关的问题。在新问题中将其单独发布。
JB Nizet

1
使用getInt返回您的int,并将int转换为字节。一个int是一个int。它的来源无关紧要。
JB Nizet

18
为什么按位运算并0xFF导致无符号整数?进行一些解释将非常有帮助。
user462455 '16

2
Java 8使用相同的方法:public static int toUnsignedInt(byte x){return((int)x)&0xff; }
Daniel DeLeón17年

55

Java 8提供Byte.toUnsignedInt了通过无符号转换byteint进行转换。在Oracle的JDK中,return ((int) x) & 0xff;由于HotSpot已经了解如何优化此模式,因此可以简单地实现它,但是可以在其他VM上实现它。更重要的是,不需要先验知识就可以了解调用的内容toUnsignedInt(foo)

总体而言,Java的8提供了方法,将byteshort无符号intlong,和int为无符号long故意省略了一种转换byte为无符号的方法,因为JVM仅提供on 且short始终提供算术。intlong

要转换一个int回一个字节,只需使用一投:(byte)someInt。所得的变窄基元转换将丢弃除最后8位以外的所有位。


7

如果只需要将期望的8位值从有符号的int转换为无符号的值,则可以使用简单的移位:

int signed = -119;  // 11111111 11111111 11111111 10001001

/**
 * Use unsigned right shift operator to drop unset bits in positions 8-31
 */
int psuedoUnsigned = (signed << 24) >>> 24;  // 00000000 00000000 00000000 10001001 -> 137 base 10

/** 
 * Convert back to signed by using the sign-extension properties of the right shift operator
 */
int backToSigned = (psuedoUnsigned << 24) >> 24; // back to original bit pattern

http://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html

如果使用非int基本类型的东西,显然您需要调整移位量:http : //docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

另外,请记住,您不能使用byte类型,这样做将导致其他应答者提​​到的带符号的值。您可以用来表示8位无符号值的最小基本类型为short


3

Integer.toString(size)调用将转换为整数的char表示形式,即char '5'。该字符的ASCII表示值为65。

您需要首先将字符串解析回整数值,例如使用Integer.parseInt,以获取原始int值。

作为底线,对于有符号/无符号转换,最好不要String显示图片,并按照@JB的建议使用位操作。


像这样吗 (此处String sizeStr = Integer.toString(size); int sizeInt = Integer.parseInt(sizeStr); byte binaryByte = Byte.valueOf((byte) sizeInt);
仍为

@Nayefc,我更新我的回答,就像你写您的评论:-)
彼得Török

好的,谢谢!由于某种原因,它仍然会打印65。这是什么意思?如果它只显示65,那么实际存储在字节中的内容就没有了。还请检查我的问题,我对其进行了编辑,并添加了有关字符串转换的部分:)
darksky 2011年

@Nayefc再次String.getBytes()产生文本中包含的字符的ASCII值,而不是数字的数字值。如上文所述,您需要将字符串解析为数字值。
彼得Török

1
@Nayefc,所以实际上是一个完全不同的问题。和AFAIS它应该工作。创建一个新问题,包括转换的实际输入和输出,以及重现该案例的完整代码。
彼得Török

3

该解决方案可以正常工作(谢谢!),但是如果您希望避免强制转换并将低级工作留给JDK,则可以使用DataOutputStream编写int的内容,并使用DataInputStream读回它们。它们将被自动视为未签名然后字节:

用于将int转换为二进制字节;

ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
int val = 250;
dos.write(byteVal);
...
dos.flush();

读回它们:

// important to use a (non-Unicode!) encoding like US_ASCII or ISO-8859-1,
// i.e., one that uses one byte per character
ByteArrayInputStream bis = new ByteArrayInputStream(
   bos.toString("ISO-8859-1").getBytes("ISO-8859-1"));
DataInputStream dis = new DataInputStream(bis);
int byteVal = dis.readUnsignedByte();

Esp。对于处理二进制数据格式(例如,平面消息格式等)很有用


3

除之外char,Java中的其他所有数字数据类型都经过签名。

如上一个答案所述,您可以通过执行and操作获得无符号值0xFF。在这个答案中,我将解释它是如何发生的。

int i = 234;
byte b = (byte) i;
System.out.println(b);  // -22

int i2 = b & 0xFF;      
// This is like casting b to int and perform and operation with 0xFF

System.out.println(i2); // 234

如果您的计算机是32位的,则int数据类型需要32位来存储值。byte只需要8位。

int变量i在存储器(作为32位整数)表示如下。

0{24}11101010

然后该byte变量b表示为:

11101010

由于bytes是无符号的,因此该值表示-22。(搜索2的补码以了解有关如何在内存中表示负整数的更多信息)

然后,如果int-22强制转换,则仍将是因为强制转换保留数字的符号。

1{24}11101010

使用进行执行操作的强制转换32-bit值。band0xFF

 1{24}11101010 & 0{24}11111111
=0{24}11101010

然后,您得到234答案。


1

使用BigInteger处理字节和无符号整数:

byte[] b = ...                    // your integer in big-endian
BigInteger ui = new BigInteger(b) // let BigInteger do the work
int i = ui.intValue()             // unsigned value assigned to i

1

尽管为时已晚,但我想对此提供意见,因为这可能会阐明JB Nizet提供的解决方案为何有效。我偶然发现了一个字节解析器和自己进行字符串转换的小问题。当您从较大尺寸的整数类型复制到较小尺寸的整数类型时,如以下java doc所述,会发生这种情况:

https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.3 将带符号整数缩小为整数类型T只会舍弃除n最低以外的所有整数阶位,其中n是用于表示类型T的位数。除了可能丢失有关数值的大小的信息外,这还可能导致结果值的符号与输入值的符号不同。

您可以确定字节是整数类型,因为此Java文档说 https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html 字节:字节数据类型是8位带符号的两位补码整数。

因此,在将整数(32位)转换为字节(8位)的情况下,只需将该整数的最后一个(最低有效8位)复制到给定的byte变量。

int a = 128;
byte b = (byte)a; // Last 8 bits gets copied
System.out.println(b);  // -128

故事的第二部分涉及Java一元和二进制运算符如何提升操作数。 https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.2 扩展基元转换(第5.1.2节)适用于转换指定的一个或两个操作数通过以下规则:

如果一个操作数的类型为double,则另一个将转换为double。

否则,如果其中一个操作数的类型为float,则另一个将转换为float。

否则,如果其中一个操作数的类型为long,则另一个将转换为long。

否则,两个操作数都将转换为int类型。

请放心,如果您使用整数类型int和/或更低的整数,它将被提升为int类型。

// byte b(0x80) gets promoted to int (0xFF80) by the & operator and then
// 0xFF80 & 0xFF (0xFF translates to 0x00FF) bitwise operation yields 
// 0x0080
a = b & 0xFF;
System.out.println(a); // 128

我也挠着这个头:)。rgettman在这里对此有很好的答案。 Java中的按位运算符仅适用于整数和长整数?


0

如果要使用原始包装器类,则可以使用,但是默认情况下所有Java类型都经过签名。

public static void main(String[] args) {
    Integer i=5;
    Byte b = Byte.valueOf(i+""); //converts i to String and calls Byte.valueOf()
    System.out.println(b);
    System.out.println(Integer.valueOf(b));
}

-1

在Java 7中

public class Main {
    public static void main(String[] args) {
        byte b =  -2;
        int i = 0 ;
        i = ( b & 0b1111_1111 ) ;
        System.err.println(i);
    }
}

结果:254

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.