Search code examples
javabufferprimitive-typesbytebuffertype-punning

Java: Using type punning on primitive arrays?


I need to be able to convert byte arrays to/from other primitive type arrays, but instead of casting, I need type punning. Correct term for raw copy without casting?

I thought it would be possible to do the following:

// 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

Unfortunately, it seems that bb.asIntBuffer() is not creating a new IntBuffer by copying the content "bitwise" or "raw", but creates a new "view" on existing ByteBuffer. That's why .array() is intended to fail.

I browsed around in JDK's sources, and found few classes, which are used by all these buffer classes and would do the stuff I need, but are internal (such as the class Unsafe).

While I think that my goal could be achieved by wrapping the byte buffer in some ObjectInputStream and read the primitive values by .readInt(), I think it would be a messy and slow workaround.

So, are there any other solutions possible without doing magical primitive type arithmetics (shifting, checking endians, ...)?

NOTE: I need both directions: byte[12] -> int[3], and int[3] -> byte[12]


Solution

  • According to the javadoc, array() [1] returns the buffer's backing array which is the array you specify with the call to wrap() [2].

    Hence, you must create a new array with the desired type. But the arithmetics can still be handled via the Buffer classes.

    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 requires a little bit of calculation by yourself.

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

    See:

    [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