在字节数组中表示一个数字(java编程)
Posted
技术标签:
【中文标题】在字节数组中表示一个数字(java编程)【英文标题】:Representing a number in a byte array (java programming) 【发布时间】:2011-02-21 13:42:01 【问题描述】:我试图在一个两字节数组中表示端口号 9876(或十六进制的 0x2694):
class foo
public static void main (String args[])
byte[] sendData = new byte[1];
sendData[0] = 0x26;
sendData[1] = 0x94;
但是我收到了一个关于可能会丢失精度的警告:
foo.java:5: possible loss of precision
found : int
required: byte
sendData[1] = 0x94;
^
1 error
如何在两字节数组中表示数字 9876 而不会丢失精度?
注意:我选择了@Björn 的代码作为正确答案,但@glowcoder 的代码也很好用。这只是解决同一问题的不同方法。谢谢大家!
【问题讨论】:
请注意,通过网络发送的扁平化数据结构通常使用 Java 中的 DataOutputStream(或其子类 ObjectOutputStream)来完成。无需每次都重新发明bitfiddling :-) @meriton: 更好的是,使用java.nio.ByteBuffer
可以做到这一切,不必处理 IOException,也可以控制字节序。
【参考方案1】:
您是否尝试过转换为字节?例如
sendData[1] = (byte)0x94;
【讨论】:
那会导致我的精度下降,不是吗? @Mark:它会让编译器清楚你正在做你想做的事。 0x94 在一个字节的范围内,所以这里没有实际的精度损失。 我以为一个字节的范围是-128到127,0x94是148 @Mark - 0x94 作为一个字节实际上不是 148,而是 -108。 @Mark:嗯……不。看位,一个字节的范围是0b00000000到0b11111111,0x94=0b10010100,正好在它的范围内。按位,“有符号字节”的概念没有任何意义。只有当您将八位序列解释为整数时,它才开始变得清晰。【参考方案2】:0x94 是十进制的 148,超出了 java 中字节的范围(-128 到 127)。 您可以执行以下操作之一:
1) 强制转换可以正常工作,因为它将保留二进制表示(对于 0x00 到 0xFF,没有有意义的位被截断):
sendData[1] = (byte)0x94;
2) 0x94 作为有符号字节的二进制表示是-108(-0x6C),所以下面的效果是一样的:
sendData[1] = -0x6C; //or -108 in decimal
【讨论】:
要将有符号字节转换回其无符号整数形式,您可以简单地写b & 0xff
。【参考方案3】:
Björn 对使用流给出了一个很好的通用答案。你也可以使用java.nio.ByteBuffer
来做同样的事情,这会导致代码稍微少一些,并且你还可以控制输出的字节序(字节顺序)。
创建字节数组:
public static byte[] toByteArray(int bits)
ByteBuffer buf = ByteBuffer.allocate(4);
buf.putInt(bits);
return buf.array();
反转它:
public static int fromByteArray(byte[] b)
ByteBuffer buf = ByteBuffer.wrap(b);
return buf.getInt();
【讨论】:
【参考方案4】:我的第一个答案是位移,但再想一想,我认为使用输出流可能会更好,更容易理解。我通常避免强制转换,但如果您不寻求通用解决方案,我想这没关系。 :)
使用流,一个通用的解决方案:
public byte[] intToByteArray(final int i) throws java.io.IOException
java.io.ByteArrayOutputStream b = new java.io.ByteArrayOutputStream();
java.io.DataOutputStream d = new java.io.DataOutputStream(b);
d.writeInt(i);
d.flush();
return b.toByteArray();
然后反转它:
public int byteArrayToInt(final byte[] b) throws IOException
java.io.ByteArrayInputStream ba = new java.io.ByteArrayInputStream(b);
java.io.DataInputStream d = new java.io.DataInputStream(ba);
return d.readInt();
【讨论】:
您也可以使用 java.nio.ByteBuffer 进行一般性操作,并在必要时控制字节序。我已经为这种可能性添加了答案。【参考方案5】:您必须转换为 (byte),因为 java 中的默认数字类型是 int,它大于 byte。只要值适合字节,就可以转换。
【讨论】:
【参考方案6】:试试这个:
sendData[0] =(byte)0x26
sendData[1] =(byte)0x94
或者这个:
sendData[0] =(byte)38
sendData[1] =(byte)148
您必须将数据转换为字节才能将其分配给字节!
这并不意味着你失去了精度,只是写 0x26
意味着一个 int 到 Java 编译器..
但还要注意:一个字节的范围是从 -128 到 127,所以在 0x94=148
的情况下,它会在字节转换后表示为 '-108' ,所以它在数学计算中不能正常工作..
【讨论】:
【参考方案7】:这是因为 Java 中的所有内容都已签名。 0x94 (148) 大于 Byte.MAX_VALUE(2^7-1)。
你需要的是
public static byte[] intToByteArray(int value)
byte[] b = new byte[4];
for (int i = 0; i < 4; i++)
int offset = (b.length - 1 - i) * 8;
b[i] = (byte) ((value >>> offset) & 0xFF);
return b;
【讨论】:
注意,这会完成 int 的所有 4 个字节......你只需要其中的两个。剩下的就很简单了。 这有两个错误——这不是因为所有内容都已签名,而是因为 0x94 是一个 int,而不是一个字节,其次是 char 类型是无符号的,第三——该代码是一个笑话吗?如果你只是在和那个人打交道,那可能值得 +1 :) 如果你用 (byte) 沮丧的话,原来的很好 0x94 是一个 int,因为它不适合字节because bytes are signed
。你是正确的,字符是无符号的 - 但是,这是规则的例外,因为它不是 intended
是一个数字 - JavaGods 决定他们的所有数字都将被签名。你能像数字一样使用它来优化字符串吗?是的你可以。它是否打算用作数字?否。Character
类是否扩展了 Number
类?不。第三,不,这段代码不是开玩笑,这是将任何 int 转换为字节数组以准确表示其位的合法方式。过去我用它来创建 TCP/IP 数据包。
我试过你的代码,效果很好。感谢您帮助初学者学习 Java!以上是关于在字节数组中表示一个数字(java编程)的主要内容,如果未能解决你的问题,请参考以下文章
以一种有效的方式使用 ByteBuffer 将标题和数据布局打包在一个字节数组中?
如何在python 3中有效地将原始字节写入numpy数组数据