如何在 Java 中初始化字节数组?
Posted
技术标签:
【中文标题】如何在 Java 中初始化字节数组?【英文标题】:How do I initialize a byte array in Java? 【发布时间】:2012-06-27 20:07:31 【问题描述】:我必须在 java 中以字节数组形式存储一些常量值 (UUID),我想知道初始化这些静态数组的最佳方法是什么。这就是我目前的做法,但我觉得必须有更好的方法。
private static final byte[] CDRIVES = new byte[] (byte)0xe0, 0x4f, (byte)0xd0,
0x20, (byte)0xea, 0x3a, 0x69, 0x10, (byte)0xa2, (byte)0xd8, 0x08, 0x00, 0x2b,
0x30, 0x30, (byte)0x9d ;
private static final byte[] CMYDOCS = new byte[] (byte)0xba, (byte)0x8a, 0x0d,
0x45, 0x25, (byte)0xad, (byte)0xd0, 0x11, (byte)0x98, (byte)0xa8, 0x08, 0x00,
0x36, 0x1b, 0x11, 0x03 ;
private static final byte[] IEFRAME = new byte[] (byte)0x80, 0x53, 0x1c,
(byte)0x87, (byte)0xa0, 0x42, 0x69, 0x10, (byte)0xa2, (byte)0xea, 0x08,
0x00, 0x2b, 0x30, 0x30, (byte)0x9d ;
...
and so on
有什么我可以使用的可能效率较低但看起来更干净的东西吗? 例如:
private static final byte[] CDRIVES =
new byte[] "0xe04fd020ea3a6910a2d808002b30309d" ;
【问题讨论】:
既然声明为static final
,这可能已经是最合适的方式了;接受的答案完全忽略了这些关键字,甚至无法使用它们。
【参考方案1】:
您可以使用 Java UUID 类来存储这些值,而不是字节数组:
UUID
public UUID(long mostSigBits,
long leastSigBits)
使用指定的数据构造一个新的 UUID。 mostSigBits 用于 UUID 的最高有效 64 位,leastSigBits 成为 UUID 的最低有效 64 位。
【讨论】:
【参考方案2】:就干净的进程而言,您可以使用 ByteArrayOutputStream 对象...
ByteArrayOutputStream bObj = new ByteArrayOutputStream();
bObj.reset();
//使用
将所有值一一写入bObjbObj.write(byte value)
// 完成后,您可以使用
获取字节[]CDRIVES = bObj.toByteArray();
//你也可以对 CMYDOCS 和 IEFRAME 重复类似的过程,
注意如果您真的有小数组,这不是一个有效的解决方案。
【讨论】:
【参考方案3】:您可以使用实用程序函数将熟悉的十六进制字符串转换为byte[]
。
当用于定义final static
常量时,性能成本无关紧要。
从 Java 17 开始
现在有java.util.HexFormat
可以让你这样做
byte[] CDRIVES = HexFormat.of().parseHex("e04fd020ea3a6910a2d808002b30309d");
如果您发现其他格式更易于阅读或从参考源复制粘贴时,此实用程序类可让您指定一种方便的格式:
byte[] CDRIVES = HexFormat.ofDelimiter(":")
.parseHex("e0:4f:d0:20:ea:3a:69:10:a2:d8:08:00:2b:30:30:9d");
Java 17 之前
我建议你使用 Dave L 在Convert a string representation of a hex dump to a byte array using Java? 中定义的函数
byte[] CDRIVES = hexStringToByteArray("e04fd020ea3a6910a2d808002b30309d");
我将其插入此处以获得最大的可读性:
public static byte[] hexStringToByteArray(String s)
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2)
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
return data;
【讨论】:
在 Java 17 中,您现在可以使用java.util.HexFormat.of().parseHex("e04fd020ea3a6910a2d808002b30309d")
@DaveL。谢谢。更新答案【参考方案4】:
在 Java 6 中,有一种方法可以完全满足您的要求:
private static final byte[] CDRIVES = javax.xml.bind.DatatypeConverter.parseHexBinary("e04fd020ea3a6910a2d808002b30309d")
您也可以使用Google Guava:
import com.google.common.io.BaseEncoding;
private static final byte[] CDRIVES = BaseEncoding.base16().lowerCase().decode("E04FD020ea3a6910a2d808002b30309d".toLowerCase());
当您使用小型数组时,Guava 方法过于矫枉过正。但是 Guava 也有可以解析输入流的版本。在处理大的十六进制输入时,这是一个很好的功能。
【讨论】:
Guava 的例子并不像写的那样工作——如果你有小写的十六进制数字,它必须是base16().lowerCase().decode(...)
。 docs.guava-libraries.googlecode.com/git/javadoc/com/google/…
@PeterDeGlopper 很好的发现,我已经更新了答案,因此代码现在可以处理带有小写和大写字符的字符串。
javax.xml.bind
在 Java 9 中不幸被删除。【参考方案5】:
byte[] myvar = "Any String you want".getBytes();
字符串文字可以转义以提供任何字符:
byte[] CDRIVES = "\u00e0\u004f\u00d0\u0020\u00ea\u003a\u0069\u0010\u00a2\u00d8\u0008\u0000\u002b\u0030\u0030\u009d".getBytes();
【讨论】:
这不是将字符串"0000"
转换为0x30,0x30,0x30,0x30
(ASCII)而不是海报所希望的0x00,0x00,0x00,0x00
(二进制)吗?
看问题的标题。然后回头看看这个答案。现在告诉我,这有什么问题?它可能无法解决海报的特定问题,但它确实解决了我的问题。我需要将字符串转换为字节数组以用作伪随机数生成器的种子,这就像一个魅力。
@e18r 它正在生成字节,是的,但你不知道是哪个,因为这依赖于默认字符集。至少使用 .getBytes(desiredEncoding)。
@petmez 愚蠢的问题:在 JAVA 中,类似于 "".getBytes(UTF_8)); (空字符串上的getBytes)安全的事情吗?它“合法”吗?或者我可以这样做: = new byte[0]; ?
@RobertAchmann "".getbytes("UTF-8") 应该返回一个空数组并且是完全合法的。【参考方案6】:
在这种情况下,我的首选选项是使用org.apache.commons.codec.binary.Hex
,它具有在String
y 十六进制和二进制之间转换的有用API。例如:
Hex.decodeHex(char[] data)
如果数组中有非十六进制字符或奇数个字符,则抛出 DecoderException
。
Hex.encodeHex(byte[] data)
对应上面的decode方法,吐出char[]
。
Hex.encodeHexString(byte[] data)
从byte
数组转换回String
。
用法:Hex.decodeHex("dd645a2564cbe648c8336d2be5eafaa6".toCharArray())
【讨论】:
【参考方案7】:private static final int[] CDRIVES = new int[] 0xe0, 0xf4, ...;
访问后转换为字节。
【讨论】:
【参考方案8】:没有库的解决方案,返回动态长度,无符号整数解释(不是二进制补码)
public static byte[] numToBytes(int num)
if(num == 0)
return new byte[];
else if(num < 256)
return new byte[] (byte)(num) ;
else if(num < 65536)
return new byte[] (byte)(num >>> 8),(byte)num ;
else if(num < 16777216)
return new byte[] (byte)(num >>> 16),(byte)(num >>> 8),(byte)num ;
else // up to 2,147,483,647
return new byte[] (byte)(num >>> 24),(byte)(num >>> 16),(byte)(num >>> 8),(byte)num ;
【讨论】:
【参考方案9】:你可以使用这个实用功能:
public static byte[] fromHexString(String src)
byte[] biBytes = new BigInteger("10" + src.replaceAll("\\s", ""), 16).toByteArray();
return Arrays.copyOfRange(biBytes, 1, biBytes.length);
与 Denys Séguret 和 stefan.schwetschke 的变体不同,它允许在输入字符串中插入分隔符(空格、制表符等),使其更具可读性。
使用示例:
private static final byte[] CDRIVES
= fromHexString("e0 4f d0 20 ea 3a 69 10 a2 d8 08 00 2b 30 30 9d");
private static final byte[] CMYDOCS
= fromHexString("BA8A0D4525ADD01198A80800361B1103");
private static final byte[] IEFRAME
= fromHexString("80531c87 a0426910 a2ea0800 2b30309d");
【讨论】:
【参考方案10】:最小的内部类型,在编译时可以用十六进制数赋值是char,如
private static final char[] CDRIVES_char = new char[] 0xe0, 0xf4, ...;
为了有一个等效的字节数组,可以将转换部署为
public static byte[] charToByteArray(char[] x)
final byte[] res = new byte[x.length];
for (int i = 0; i < x.length; i++)
res[i] = (byte) x[i];
return res;
public static byte[][] charToByteArray(char[][] x)
final byte[][] res = new byte[x.length][];
for (int i = 0; i < x.length; i++)
res[i] = charToByteArray(x[i]);
return res;
【讨论】:
【参考方案11】:您可以使用充气城堡包,
Maven 导入,
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
Java 代码,
byte[] CDRIVES = Hex.decode("e04fd020ea3a6910a2d808002b30309d");
【讨论】:
以上是关于如何在 Java 中初始化字节数组?的主要内容,如果未能解决你的问题,请参考以下文章