我需要将数字转换为无符号字节。该数字始终小于或等于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
。有什么建议吗?
答案 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提供了将byte
和short
转换为无符号int
和long
以及将int
转换为无符号long
的方法。将byte
转换为无符号short
的方法是deliberately omitted,因为JVM只提供int
和long
的算术。
要将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)
.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。