如何将Int转换为无符号字节和后退

时间:2011-09-13 12:04:23

标签: java byte int

我需要将数字转换为无符号字节。该数字始终小于或等于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。有什么建议吗?

12 个答案:

答案 0 :(得分:180)

一个字节始终用Java签名。您可以通过二进制获取其无符号值,并使用0xFF,但是:

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

答案 1 :(得分:42)

Java 8提供Byte.toUnsignedInt通过无符号转换将byte转换为int。在Oracle的JDK中,这只是实现为return ((int) x) & 0xff;,因为HotSpot已经了解如何优化这种模式,但它可以在其他VM上实现内在化。更重要的是,不需要先验知识来了解toUnsignedInt(foo)的调用内容。

总的来说,Java 8提供了将byteshort转换为无符号intlong以及将int转换为无符号long的方法。将byte转换为无符号short的方法是deliberately omitted,因为JVM只提供intlong的算术。

要将int转换回字节,只需使用强制转换:(byte)someInt。结果narrowing primitive conversion将丢弃除最后8位之外的所有内容。

答案 2 :(得分:7)

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

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 :(得分:3)

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

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

作为底线,对于有符号/无符号转换,最好将String从图片中删除,并使用位操纵,如@JB所示。

答案 4 :(得分:2)

解决方案工作正常(谢谢!),但是如果你想避免强制转换并将低级别的工作留给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。用于处理二进制数据格式(例如扁平消息格式等)

答案 5 :(得分: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

答案 6 :(得分:1)

即使为时已晚,我也想对此发表意见,因为这可能会阐明JB Nizet提供的解决方案为何有效。我偶然发现了这个小问题,我在处理字节解析器并自己进行字符串转换。 当您将此Java文档从较大尺寸的整数类型复制到较小尺寸的整数类型时,会发生这种情况:

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整数类型,它将被提升为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在这里对此有很好的答案。 Bitwise operators in java only for integer and long?

答案 7 :(得分: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));
}

答案 8 :(得分:0)

除了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

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

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

1{24}11101010

32-bit的强制转换b值对and执行0xFF操作。

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

然后您将得到234作为答案。

答案 9 :(得分:0)

在可读性方面,我更喜欢Guava's

  • UnsignedBytes.checkedCast(long) 将有符号数转换为无符号字节。
  • UnsignedBytes.toInt(byte) 将无符号字节转换为有符号整数。

答案 10 :(得分:-1)

<7>中的

.appspot.com

结果:254

答案 11 :(得分:-1)

我已经测试并理解它。 在Java中,byte是有符号的,所以一个有符号字节中的234是-22,在二进制中是“11101010”,有符号位是“1”,所以用负数表示2的补码就变成了-22。 并以 0xFF 操作,将 234 转换为 2 字节有符号(32 位),保持所有位不变。

我使用 String 来解决这个问题:

int a = 14206;
byte[] b = String.valueOf(a).getBytes();
String c = new String(b);
System.out.println(Integer.valueOf(c));

输出为 14206。