前言
大約5年前,想研究javaassistant,cglib等位元組碼操作的相關類別庫,來對class進行增強,當要到要操作位元組碼的時候,發現無法繼續下去了,看不懂,只能放棄,
學習jvm位元組碼,需要理解class的組成方式,對匯編,操作堆疊比較了解,無奈,只好重新學習編譯原理,匯編等知識,再來看jvm規范,現在理解起來,容易很多了,
Class檔案規范
編譯后被 Java 虛擬機所執行的代碼使用了一種平臺中立(不依賴于特定硬體及作業系統的)
的二進制格式來表示,并且經常(但并非絕對)以檔案的形式存盤,因此這種格式被稱為 Class
檔案格式,Class 檔案格式中精確地定義了類與介面的表示形式,包括在平臺相關的目標檔案格
式中一些細節上的慣例
相關檔案
https://docs.oracle.com/javase/specs/jvms/se15/html/jvms-4.html
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
下面,我們開始決議每個欄位是如何標識出來的
其中 u4, u2 代表什么意思
u 表示無符號數 后面的數字 表示 占用多少位元組
u4 占用4個位元組
u2 占用2個位元組
- magic 占用4個位元組,(ca fe ba be )

-
minor_version 子版本號 ,2個位元組數字

-
major_version 主版本好 2個位元組的數字

- constant_pool_count 常量池數目 2個位元組的數字

- constant_pool[constant_pool_count-1] 常量池陣列

- access_flags 訪問標識 2個位元組數字
- this_class class名稱的索引,
- super_class 超類的名稱索引
- interfaces_count 介面的數目
- interfaces[interfaces_count] 介面的陣列
- fields_count 欄位數目
- fields[fields_count] 欄位的陣列
- methods_count 方法的數目
- methods[methods_count] 方法的陣列
- attributes_count 屬性的數目
- attributes[attributes_count] 屬性的陣列
如何自己動手解一個class檔案
相信大部分第一次看到上面的協議時候,能看懂,但是要自己動手決議出每個欄位的含義出來,
就無法下手了,
- 讀取class檔案
FileInputStream in= new FileInputStream("d:/my.class");
- 讀取 magic ,(magic u4 占用4個位元組)
byte[] bytes=new byte[4];
in.read(bytes);
- 讀取 minor_version u2 占用2個位元組
byte[] minorByte=new byte[2];
in.read(minorByte);
- 讀取 major_version u2 占用2個位元組
byte[] majorVersion=new byte[2];
in.read(majorVersion);
看到上面的決議,是否明白了,其實還是很有規律的,只要你認真看協議檔案(要看好多遍才行)
最終決議class 檔案就是這樣的
ClassFile classFile = new ClassFile();
PcBufferInputStream in = new PcBufferInputStream(new FileInputStream(fileName));
classFile.setMagic(readMagic(in));
classFile.setMinorVersion(readMinorVersion(in));
classFile.setMajorVersion(readMajorVersion(in));
classFile.setConstantPoolCount(readConstantPoolCount(in));
classFile.setCpInfo(readCpInfo(in));
classFile.setAccessFlags(readAccessFlags(in));
classFile.setThisClass(readThisClass(in));
classFile.setSuperClass(readSuperClass(in));
classFile.setInterfacesCount(readInterfacesCount(in));
// u2 interfaces interfaces_count
classFile.setInterfaces(readInterfaces(in));
// u2 fields_count
classFile.setFieldsCount(readFieldsCount(in));
// field_info fields fields_count
classFile.setFields(readFields(in));
// u2 methods_count 1
// method_info methods methods_count
classFile.setMethodsCount(readMethodsCount(in));
classFile.setMethods(readMethods(in));
// u2 attribute_count 1
classFile.setAttributeCount(readAttributeCount(in));
// attribute_info attributes attributes_count
classFile.setAttributes(readAttributes(in));
classFile.setPcRecord(recordMap);
return classFile;
java class 決議原始碼開源地址
https://gitee.com/venus-suite/java-classViewer
如果喜歡,歡迎stars 哦
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/458364.html
標籤:其他
