4

我需要能够将字节数组转换为其他原始类型数组/从其他原始类型数组转换,但我需要类型 punning而不是强制转换。没有强制转换的原始副本的正确术语?

我认为可以执行以下操作:

// idea: byte[12] -> int[3], and int[3] -> byte[12]

int[] ints;

ByteBuffer bb = ByteBuffer.wrap(
    new byte[]{ 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3 });
IntBuffer ib = bb.asIntBuffer();

ints = ib.array(); // java.lang.UnsupportedOperationException
ints = ib.duplicate().array(); // java.lang.UnsupportedOperationException

不幸的是,似乎bb.asIntBuffer()不是通过“按位”或“原始”复制内容来创建新的 IntBuffer,而是在现有 ByteBuffer 上创建新的“视图” 这就是为什么.array()打算失败。

我浏览了 JDK 的源代码,发现了一些类,所有这些缓冲区类都使用这些类并且可以做我需要的东西,但是是内部的(例如 class Unsafe)。

虽然我认为可以通过将字节缓冲区包装在一些中ObjectInputStream并通过读取原始值来实现我的目标.readInt(),但我认为这将是一个混乱且缓慢的解决方法。

那么,如果不进行神奇的原始类型算术(移位、检查字节序……),还有其他可能的解决方案吗?

注意:我需要两个方向:byte[12] -> int[3] 和 int[3] -> byte[12]

4

2 回答 2

6

根据 javadoc,array() [1] 返回缓冲区的支持数组,这是您通过调用 wrap() [2] 指定的数组。

因此,您必须创建一个具有所需类型的新数组。但是算术仍然可以通过 Buffer 类来处理。

ByteBuffer bb = ByteBuffer.wrap(new byte[]{ 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3 });
IntBuffer ib = bb.asIntBuffer();

int[] intArray = new int[ib.limit()];
ib.get(intArray);

Backwards 需要自己进行一些计算。

ByteBuffer newBb = ByteBuffer.allocate(intArray.length*4);
newBb.asIntBuffer().put(intArray);
byte[] byteArray = newBb.array();

看:

[1] http://java.sun.com/javase/6/docs/api/java/nio/ByteBuffer.html#array%28%29

[2] http://java.sun.com/javase/6/docs/api/java/nio/ByteBuffer.html#wrap%28byte[]%29

于 2010-02-13T08:11:36.960 回答
1

非常感谢wierob提供的用于转换 byte[]->int[] 的代码!

我玩了一下,以使相反的方向起作用。

1) API

// byte[] -> int[]
public static int[] punnedToInteger(byte[] in){
    ByteBuffer bb = ByteBuffer.wrap(in);
    IntBuffer pb = bb.asIntBuffer();

    int[] out = new int[pb.limit()];
    pb.get(out);

    return out;
}

// int[] -> byte[]
public static byte[] punnedFromInteger(int[] in){
    byte[] out = new byte[in.length * Integer.SIZE / Byte.SIZE];
    ByteBuffer bb = ByteBuffer.wrap(out);

    for(int i=0; i<in.length; ++i){
        bb.putInt(in[i]);
    }

    return out;
}

2) 测试用例

{
    byte[] bytes = new byte[]{ 0,0,0,1, 0,0,1,0, 0,1,0,0, 1,0,0,0 };
    int[] ints = punnedToInteger(bytes);
    System.out.println(Arrays.toString(bytes));
    System.out.println(Arrays.toString(ints));
    System.out.println();
}
{
    int[] ints = new int[]{ 1, 256, 65536, 16777216 };
    byte[] bytes = punnedFromInteger(ints);
    System.out.println(Arrays.toString(ints));
    System.out.println(Arrays.toString(bytes));
    System.out.println();
}

3) 输出

[0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0]
[1, 256, 65536, 16777216]

[1, 256, 65536, 16777216]
[0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0]
于 2010-02-13T09:26:45.240 回答