調用ByteBuffer.getInt()方法遇到的奇怪錯誤
最近在參加阿里的中間件比賽,中間用到了RocketMQ的思想,並且主要集中在使用NIO來讀寫文件。其中遇到了一個很蛋疼的問題,想了半天想不出來為什么,現已解決並來記錄一下。
先上代碼:
@Test
public void test() throws IOException {
FileChannel fc = new RandomAccessFile(STORE_PATH, "rw").getChannel();
ByteBuffer byteBuffer = fc.map(FileChannel.MapMode.READ_WRITE, 0, 1024);
int a = byteBuffer.getInt();
System.out.println(a);
}
代碼主要使用了Java NIO中的FileChannel和ByteBuffer,目的是讀取文件中的四個字節,並將其轉為int類型的數字,對於這個文件我手動輸入了四個'0',按照我的想法,讀出來應該還是會為0。然而結果卻如下:
808464432
這是個什么鬼?試了幾次都是一樣的數字,覺得很奇怪,為什么不是0呢。看了下ByteBuffer.getInt()的源碼,發現ByteBuffer是一個抽象類,該方法有兩種實現方式,分別是DirectByteBuffer和HeapByteBuffer,其中NIO使用的DirectByteBuffer,所以看下源碼:
private int getInt(long a) {
if (unaligned) {
int x = unsafe.getInt(a);
return (nativeByteOrder ? x : Bits.swap(x));
}
return Bits.getInt(a, bigEndian);
}
public int getInt() {
return getInt(ix(nextGetIndex((1 << 2))));
}
其中調用的是Unsafe包下的getInt()的native方法,好像又遇到死胡同了。
最后沒招了,突發奇想搜了一下808464432這個數字,搜到
int變量的值為808464432 是為什么?內存越界?被賦錯值?這篇博客,其中的一段話很明確的解釋了原因:
808464432,是10進制數,轉換為16進制是0x30303030,0x30是字符'0'的ASCII碼的16進制表示,也就是說,808464432這個數字,對應字符串“0000”,一個int變量,占4個字節,如果每個字節都寫入一個字符'0',那么就會是這個數。
原來是因為我輸入的時候是以字符形式輸入到文件,稍微修改一下代碼,果然就好了,代碼和結果如下:
@Test
public void test() throws IOException {
FileChannel fc = new RandomAccessFile(STORE_PATH, "rw").getChannel();
ByteBuffer byteBuffer = fc.map(FileChannel.MapMode.READ_WRITE, 0, 1024);
byteBuffer.putInt(0,1);
int a = byteBuffer.getInt();
System.out.println(a);
}