如何将字节数组转换为整数数组而无需复制

huangapple go评论72阅读模式
英文:

How to convert a Byte Array to an Int Array without copying

问题

已有一个解决方案,但涉及内存复制。我希望有一个不涉及内存复制的解决方案。在这种情况下,保证输入的字节数组(byte[])的字节数是4的倍数,以便可以将其转换为整数数组(int[])而无需填充/重新分配内存。

在C中,这很容易实现。我希望在Java中(特别是在Android上)实现类似的功能。以下是C版本:

// 输入字节数组
// 注意,字节数(char)是4的倍数(即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

// 将其转换为整数数组
// 注意,它不涉及内存复制
int* integer_array = (int *) byte_array;

// 打印整数数组的第一个整数
// 它将打印:0x64636261或0x61626364,具体取决于字节序
printf("0x%X\n", integer_array[0]);

在Java中是否真的可以实现类似的功能(即无内存复制)?

英文:

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?

答案1

得分: 2

不,这是不可能的。

在Java中,数组不能轻易地重新解释为其他类型。数组对象的内存布局包括指向数组类的指针和数组的长度。没有任何操作可以让你覆盖现有数组的类指针和长度字段。

你可以使用java.nio中的“缓冲区”对象来做类似的事情,但实际上并不相同。你可以创建一个包装字节数组的ByteBuffer对象。然后,你可以从字节缓冲区获取一个IntBuffer "view"。这些对象只是访问字节数组中的数据的视图,不会复制任何数据。以下代码会输出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);
// 将CPU本机字节顺序设置为启用优化
byteBuffer.order(ByteOrder.nativeOrder());

IntBuffer intBuffer = byteBuffer.asIntBuffer();
System.out.printf("0x%X\n", intBuffer.get(0));
英文:

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

答案2

得分: 0

你可以将其转换为 List<Integer> 而不是转换为 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;
    }

}

以及

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

输出

list.get(0) = 0x61626364

修改此列表将修改原始字节数组

```java
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();

输出:

byteArray = 0x12 0x34 0x56 0x78

你可以对 ByteArrayIntList 应用 .sort().stream().iterator()。由于 ByteArrayIntList 是一个固定长度的列表,.add() 会抛出 UnsupportedOperationException

英文:

You can convert to List&lt;Integer&gt; without copying instead of converting to int[].

public class ByteArrayIntList extends AbstractList&lt;Integer&gt; {

    private final int size;
    private final IntBuffer intBuffer;

    public ByteArrayIntList(byte[] array) {
        if (array.length % 4 != 0)
            throw new IllegalArgumentException(&quot;array&quot;);
        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 = {&#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39;};
System.out.println(Arrays.toString(byteArray));
ByteArrayIntList list = new ByteArrayIntList(byteArray);
System.out.printf(&quot;list.get(0) = 0x%08x%n&quot;, list.get(0));

output:

list.get(0) = 0x61626364

Modifying this list will modify the original byte array.

list.set(0, 0x12345678);
System.out.print(&quot;byteArray = &quot;);
for (int i = 0; i &lt; byteArray.length; ++i)
    System.out.printf(&quot;0x%02x &quot;, 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.

huangapple
  • 本文由 发表于 2020年8月15日 02:38:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/63418367.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定