如何在Java中初始化字节数组?


138

我必须在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" };

Answers:


111

使用将十六进制字符串转换为的函数byte[],您可以执行

byte[] CDRIVES = hexStringToByteArray("e04fd020ea3a6910a2d808002b30309d");

我建议您使用Dave L定义的函数,使用Java将十六进制转储的字符串表示形式转换为字节数组吗?

我将其插入此处以获得最大的可读性:

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;
}

如果让CDRIVES staticfinal,则性能下降无关紧要。


78
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();

50
这样是否不会按照发布者的要求将字符串转换"0000"{0x30,0x30,0x30,0x30}(ASCII)而不是{0x00,0x00,0x00,0x00}(二进制)?
jww 2014年

5
看问题的标题。然后回头看看这个答案。现在告诉我,这怎么了?它可能无法解决发布者的特定问题,但肯定可以解决我的问题。我需要将字符串转换为字节数组,以用作伪随机数生成器的种子,这就像一个魅力。
e18r

@ e18r它正在生成字节,是的,但是您不知道哪个字节,因为此依赖于默认字符集。至少使用.getBytes(desiredEncoding)。
定量

@petmez愚蠢的问题:在JAVA中,类似于“” .getBytes(UTF_8)); (将getBytes放在一个空字符串上)安全吗?是“合法的”吗?或者我可以做:= new byte [0]; ?
罗伯特·阿赫曼

1
@RobertAchmann“” .getbytes(“ UTF-8”)应该返回一个空数组,并且完全合法。
Jazzepi

33

在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示例不能完全按照书面形式工作- base16().lowerCase().decode(...)如果您使用小写的十六进制数字,则需要这样做。docs.guava-libraries.googlecode.com/git/javadoc/com/google/...
彼得DeGlopper

@PeterDeGlopper很好的发现,我已经更新了答案,因此代码现在可以同时处理大小写字符的字符串。
stefan.schwetschke

1
javax.xml.bind在Java中9是可悲的去除
randomdude999

7

您可以使用Java UUID类来存储这些值,而不是字节数组:

UUID

public UUID(long mostSigBits,
            long leastSigBits)

使用指定的数据构造一个新的UUID。mostSigBits用于UUID的最高有效64位,而minimumSigBits成为UUID的最低有效64位。


2

至于干净的过程,您可以使用ByteArrayOutputStream对象...

ByteArrayOutputStream bObj = new ByteArrayOutputStream();
bObj.reset();

//使用以下命令将所有值一一写入bObj

bObj.write(byte value)

//完成后,您可以使用

CDRIVES = bObj.toByteArray();

//比起您也可以对CMYDOCS和IEFRAME重复类似的过程,

注意如果您的阵列确实很小,这不是一个有效的解决方案。


2

没有库,动态长度返回,无符号整数解释(非二进制补码)的解决方案

    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 };
    }
}

1

在这种情况下,我的首选方法是使用org.apache.commons.codec.binary.Hex具有有用的API的Stringy十六进制和二进制之间的转换。例如:

  1. Hex.decodeHex(char[] data)DecoderException如果数组中有非十六进制字符,或者字符数为奇数,则抛出。

  2. Hex.encodeHex(byte[] data)是与上述解码方法相对应的,并吐出char[]

  3. Hex.encodeHexString(byte[] data)byte数组转换回String

用法: Hex.decodeHex("dd645a2564cbe648c8336d2be5eafaa6".toCharArray())


1

您可以使用以下实用程序功能:

public static byte[] fromHexString(String src) {
    byte[] biBytes = new BigInteger("10" + src.replaceAll("\\s", ""), 16).toByteArray();
    return Arrays.copyOfRange(biBytes, 1, biBytes.length);
}

与DenysSé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");

1

最小的内部类型(在编译时可以用十六进制数字指定)是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;
}

-2
private static final int[] CDRIVES = new int[] {0xe0, 0xf4, ...};

访问后转换为字节。

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.