Android坑点-ByteBuffer.array() 入过坑吗
目錄
- 1、坑點介紹
- 2、正確使用姿勢(入坑了怎么辦)
- 3、坑坑詳解
- 3.1HeapByteBuffer可以用buffer.array()
- 3.2DirectByteBuffer的坑在哪里
1、坑點介紹
如下代碼:
ByteBuffer buffer = ByteBuffer.allocateDirect(int capacity) byte[] array = buffer.array()在android平臺前面會有幾個字節是沒有實際數據的,在jre環境下,發生異常。
怎么理解呢?
來個栗子:
結果如下:
2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[0]=0
2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[1]=0
2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[2]=0
2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[3]=0
2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[4]=1
2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[5]=2
2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[6]=0
2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[7]=0
2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[8]=0
2021-10-27 15:29:43.169 D/BufferTester: bufferTest arr[9]=0
通過上面的結果可以看到 arr[4]=1, arr[5]=2。我們是put了1和2,正常情況是從數組第一個元素開始寫入,我們取出的數組卻跳躍了前面4個字節。
2、正確使用姿勢(入坑了怎么辦)
實際上buffer.array() 是不能用的,我們需要使用get(byte[] dst) 或get(byte[] dst, int offset, int length),具體代碼如下
private void bufferTest() {ByteBuffer buffer = ByteBuffer.allocateDirect(10);buffer.put((byte) 1);buffer.put((byte) 2); // byte[] arr = buffer.array();buffer.position(0);byte []arr = new byte[10];//put 2次,實際是2個字節buffer.get(arr);for (int i = 0; i < 10; i++) {Log.d("BufferTester", "bufferTest arr[" + i + "]=" + arr[i]);}}結果:
2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[0]=1
2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[1]=2
2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[2]=0
2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[3]=0
2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[4]=0
2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[5]=0
2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[6]=0
2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[7]=0
2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[8]=0
2021-10-27 15:53:49.954 D/BufferTester: bufferTest arr[9]=0
arr[0]=1,arr[1]=2 是我們期望的結果,也是正確結果。
注:put一字節,postion+1,所以上述代碼在取的時候,將pos恢復到起始位置。
所以請使用get方法來獲取內容。
如果還是要用array(),那么一定要完全掌握好DirectByteBuffer的機制。
3、坑坑詳解
ByteBuffer是一個抽象類,通過類函數 allocateDirect(int capacity)創建的是DirectByteBuffer對象;通過類函數allocate(int capacity)創建的是HeapByteBuffer對象。關系和代碼如下
簡單過一下:HeapByteBuffer 是堆上分配的空間,DirectByteBuffer是系統分配的空間。
3.1HeapByteBuffer可以用buffer.array()
private HeapByteBuffer(int cap, int lim, boolean isReadOnly) {super(-1, 0, lim, cap, new byte[cap], 0);this.isReadOnly = isReadOnly;}因為調用super的時候,就 按照給定的大小(new byte[cap]) 分配了數組傳遞給父類,最終調用array()的時候,就返回的這個數組。
3.2DirectByteBuffer的坑在哪里
注意了,我們重點看兩個構造函數
DirectByteBuffer.MemoryRef memoryRef = new DirectByteBuffer.MemoryRef(capacity);
return new DirectByteBuffer(capacity, memoryRef);
注意看注釋要點1、2、3:
也許老鐵已經看出了端倪,此處傳遞給父類的數組是capacity + 7長度的,其中address是數組的一個子集,舉個例子,如果capacity = 10,offset = 5,那么buffer的長度是17,allocatedAddress 是buffer[0]的地址,address 就是buffer[5] 地址。
總體來說DirectByteBuffer分配了一個字節數組buffer 長度capacity+7,并計算出了一個小于7的偏移值x,再得到一個buffer的偏移地址,address = buffer+x。put、get都是通過address來存取的,因偏移,存取起始位置不一定是buffer[0],array() 返回的是buffer,因此可能存在前面x個字節沒有值。
參數給的10,buffer實際長度17:
2021-10-27 17:18:14.740 D/BufferTester: bufferTest len = 17
同時在jre的環境下,DirectByteBuffer的實現稍有區別,沒有偏移,且array被調用會拋出異常。沒有計算offset也沒有持有數組對象,只通過一個地址進行存取。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的Android坑点-ByteBuffer.array() 入过坑吗的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从零开始学java 框架_从零开始学 J
- 下一篇: Android面试基础一