0

There is already a solution but it involves memory copying. I want a solution that does not involve memory copying. In this scenario, it is guaranteed that the input byte array (byte[]) must consist of the number of bytes being the multiple of 4 so that it can be converted to an integer array (int[]) without padding/reallocation.

This is very easy to do in C. I want the similar thing in Java (specifically on Android). Here is the C version:

// input byte array
// note that the number of bytes (char) is the multiple of 4 (i.e., sizeof(int)).
char* byte_array = calloc(100, sizeof(int));
byte_array[0] = 'a'; // 0x61
byte_array[1] = 'b'; // 0x62
byte_array[2] = 'c'; // 0x63
byte_array[3] = 'd'; // 0x64

// converting it to an integer array
// note that it does not involve memory copying
int* integer_array = (int *) byte_array;

// printing the first integer of the integer array
// it will print: 0x64636261 or 0x61626364, depending on the endianness 
printf("0x%X\n", integer_array[0]);

Is it really possible to do the similar thing (i.e., no memory copying) in Java?

arnobpl
  • 1,126
  • 4
  • 16
  • 32

2 Answers2

2

No it is not possible.

Arrays in Java cannot be easily re-interpreted as other types. The memory layout for an array object includes a pointer to the array class, and the array's length. There are no operations that would allow you to overwrite the class pointer and the length field of an existing array.

You can do something similar using "buffer" objects from java.nio but it's not really the same. You can create a ByteBuffer object that wraps an array of bytes. You can then get an IntBuffer "view" from the byte buffer. No data is copied, as these objects are simply views that access data in the byte array. This prints out 0x64636261:

byte[] byte_array = new byte[128];
byte_array[0] = 'a'; // 0x61
byte_array[1] = 'b'; // 0x62
byte_array[2] = 'c'; // 0x63
byte_array[3] = 'd'; // 0x64

ByteBuffer byteBuffer = ByteBuffer.wrap(byte_array);
// set CPU-native byte order to enable optimizations
byteBuffer.order(ByteOrder.nativeOrder());

IntBuffer intBuffer = byteBuffer.asIntBuffer();
System.out.printf("0x%X\n", intBuffer.get(0));
Joni
  • 108,737
  • 14
  • 143
  • 193
0

You can convert to List<Integer> without copying instead of converting to int[].

public class ByteArrayIntList extends AbstractList<Integer> {

    private final int size;
    private final IntBuffer intBuffer;

    public ByteArrayIntList(byte[] array) {
        if (array.length % 4 != 0)
            throw new IllegalArgumentException("array");
        this.size = array.length / 4;
        this.intBuffer = ByteBuffer.wrap(array).asIntBuffer();
    }

    @Override
    public Integer get(int index) {
        return intBuffer.get(index);
    }

    @Override
    public Integer set(int index, Integer element) {
        int oldValue = get(index);
        intBuffer.put(index, element);
        return oldValue;
    }

    @Override
    public int size() {
        return size;
    }

}

and

byte[] byteArray = {'a', 'b', 'c', 'd'};
System.out.println(Arrays.toString(byteArray));
ByteArrayIntList list = new ByteArrayIntList(byteArray);
System.out.printf("list.get(0) = 0x%08x%n", list.get(0));

output:

list.get(0) = 0x61626364

Modifying this list will modify the original byte array.

list.set(0, 0x12345678);
System.out.print("byteArray = ");
for (int i = 0; i < byteArray.length; ++i)
    System.out.printf("0x%02x ", byteArray[i]);
System.out.println();

output:

byteArray = 0x12 0x34 0x56 0x78

You can apply .sort(), .stream(), and .iterator() to ByteArrayIntList. Since ByteArrayIntList is a fixed length list, .add() throws UnsupportedOperationException.