一、背景
在Java手寫JVM時,需要讀取 .class
后綴的字節碼文件。當把字節碼文件以 byte[]
(比特數組)的形式讀取到內存中時,數組前四個字節為 0xCAFEBABE
。
如何判斷我讀取的四個字節的值等於 0xCAFEBABE
呢?
二、單個字節轉int
2.1 正確代碼
public class Test {
public static void main(String[] args) {
int ca = (byte)0xca;
int fe = (byte)0xfe;
int ba = (byte)0xba;
int be = (byte)0xbe;
System.out.println(ca);
System.out.println(fe);
System.out.println(ba);
System.out.println(be);
}
}
輸出結果:
-54 -2 -70 -66
2.2 錯誤示例
int ca = 0xca; // 值為 202
2.3 錯誤原因分析
0xca
轉化為二進制為 11001010
int
型占4個字節:
十進制 | 二進制(雙字) |
---|---|
-54 | 1111 1111 1111 1111 1111 1111 1100 1010 |
202 | 0000 0000 0000 0000 0000 0000 1100 1010 |
表格中數據的正確性,可以借助 Windows 系統的計算器來表示:
長度占1個字節的byte轉化為長度為4個字節的int,高位補充和符號位相同的值,可以保持值的不變。
如果是負數,符號位為1,擴展位數時,高位補1:
負數 | 原碼 | 補碼 | 擴展為32位補碼 | 32位原碼 | 結果 |
---|---|---|---|---|---|
-54 | 1011 0110 | 1100 1010 | 1111 1111 1111 1111 1111 1111 1100 1010 | 1000 0000 0000 0000 0000 0000 0011 0110 | -54 |
但是,如果直接聲明為整型,則直接把 1100 1010 作為低8位,剩余高32位全是 0。
三、字節數組轉int
有了第二節的結論,我們這里可以用int來表示字節。
public class Test {
public static void main(String[] args) {
byte[] cafebabe = new byte[]{-54,-2,-70,-66};
int result = toInt(cafebabe);
System.out.println(Integer.toHexString(result));
}
private static int toInt(byte[] bytes) {
int result = 0;
for (int i = 0; i < 4; i++) {
result <<= 8;
result |= bytes[i] & 0xFF;
}
return result;
}
}
輸出結果:
cafebabe
說明這里的 toInt
方法是正確的。