二进制 java Class文件解析实例
先上class文件的格式。
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];
????}
其中,u2代表2個字節的無符號整數。u4代表4個字節的無符號整數,其他如cp_info、 field_info
是一些結構數據,接下去會講。
這次要解析的是一個非常簡單的類:TJ.java,代碼如下:
public?class?TJ
{
????private?final?int?f1?=?2;
????public?int?m1(int?i){
????????return?i+1;
????}
????private?void?m2(){
????}
}
使用jdk1.6編譯,產生的二進制類文件如下: CA?FE?BA?BE?00?00?00?32?00?16?0A?00?04?00?12?09
00?03?00?13?07?00?14?07?00?15?01?00?02?66?31?01
00?01?49?01?00?0D?43?6F?6E?73?74?61?6E?74?56?61
6C?75?65?03?00?00?00?02?01?00?06?3C?69?6E?69?74
3E?01?00?03?28?29?56?01?00?04?43?6F?64?65?01?00
0F?4C?69?6E?65?4E?75?6D?62?65?72?54?61?62?6C?65
01?00?02?6D?31?01?00?04?28?49?29?49?01?00?02?6D
32?01?00?0A?53?6F?75?72?63?65?46?69?6C?65?01?00
07?54?4A?2E?6A?61?76?61?0C?00?09?00?0A?0C?00?05
00?06?01?00?02?54?4A?01?00?10?6A?61?76?61?2F?6C
61?6E?67?2F?4F?62?6A?65?63?74?00?21?00?03?00?04
00?00?00?01?00?12?00?05?00?06?00?01?00?07?00?00
00?02?00?08?00?03?00?01?00?09?00?0A?00?01?00?0B
00?00?00?26?00?02?00?01?00?00?00?0A?2A?B7?00?01
2A?05?B5?00?02?B1?00?00?00?01?00?0C?00?00?00?0A
00?02?00?00?00?01?00?04?00?03?00?01?00?0D?00?0E
00?01?00?0B?00?00?00?1C?00?02?00?02?00?00?00?04
1B?04?60?AC?00?00?00?01?00?0C?00?00?00?06?00?01
00?00?00?06?00?02?00?0F?00?0A?00?01?00?0B?00?00
00?19?00?00?00?01?00?00?00?01?B1?00?00?00?01?00
0C?00?00?00?06?00?01?00?00?00?0B?00?01?00?10?00
00?00?02?00?11 下面對照上面的格式結構一點點的解析。CA FE BA BE:頭四個字節是魔數,表示這是java class文件。00 00:次版本為0。00 32:主版本0x32,表示jdk1.6編譯的。Jdk1.5為0x31,jdk1.4為0x30。00 16:常量池的入口(entry)數量。包括自己本身(這里很奇怪),所以接下來有21項的常量池入口。我會在每個常量池項的前面表上索引。常量池的第一個字節表示類型。具體類型對照表如下:
| CONSTANT_Class | 7 |
| CONSTANT_Fieldref | 9 |
| CONSTANT_Methodref | 10 |
| CONSTANT_InterfaceMethodref | 11 |
| CONSTANT_String | 8 |
| CONSTANT_Integer | 3 |
| CONSTANT_Float | 4 |
| CONSTANT_Long | 5 |
| CONSTANT_Double | 6 |
| CONSTANT_NameAndType | 12 |
| CONSTANT_Utf8 | 1 |
到此,常量池結束。
00 21:類的描述符為public。
00 03 :this class為常量池第三個,TJ,即這個類的名字為TJ
00 04:super class為常量池第四個,java/lang/Object,即它的超類為java.lang.Object
00 00:接口個數0。
00 01:field數量1。
00 12 00 05 00 06 00 01 00 07 00 00 00 02 00 08:field的結構如下
field_info {
??? ?u2 access_flags;
??? ?u2 name_index;
??? ?u2 descriptor_index;
??? ?u2 attributes_count;
??? ?attribute_info attributes[attributes_count];
??? }
access_flags為00 12,代表ACC_PRIVATE+ ACC_FINAL
name_index:常量池索引為5的入口,即f1,即類成員的名字為f1
descriptor_index:I,代表integer。
?attributes_count:1個。
attribute_info:
attribute_info {
??? ?u2 attribute_name_index;
??? ?u4 attribute_length;
??? ?u1 info[attribute_length];
}
attribute_name_index:7,即ConstantValue,結構如下
ConstantValue_attribute {
??? ?u2 attribute_name_index;
??? ?u4 attribute_length;
??? ?u2 constantvalue_index;
??? }
attribute_length:2
constantvalue_index:2
----------------------------------------下面開始方法
00 03:3個方法。
method_info {
??? ?u2 access_flags;
??? ?u2 name_index;
??? ?u2 descriptor_index;
??? ?u2 attributes_count;
??? ?attribute_info attributes[attributes_count];
??? }
--------------------------------------------第一個方法<init>,這個是編譯器產生的生成實例的初始化方法。
access_flags:public
name_index:00 09,<init>
descriptor_index:00 0A,()V表示無參數,返回void
attributes_count :00 01,1個
attribute_name_index :00 0B ,code
attribute_length:38個
Code_attribute {
??? ?u2 attribute_name_index;
??? ?u4 attribute_length;
??? ?u2 max_stack;
??? ?u2 max_locals;
??? ?u4 code_length;
??? ?u1 code[code_length];
??? ?u2 exception_table_length;
??? ?{??? ?u2 start_pc;
??? ?????? ?u2 end_pc;
??? ?????? ?u2? handler_pc;
??? ?????? ?u2? catch_type;
??? ?}?exception_table[exception_table_length];
??? ?u2 attributes_count;
??? ?attribute_info attributes[attributes_count];
??? }
max_stack: 00 02
max_locals: 00 01
code_length: 00 00 00 0A,10
code: 2A B7 00 01 2A 05 B5 00 02 B1,指令
exception table length:00 00
attributes_count:1
attribute_name_index:00 0C,LineNumberTable
LineNumberTable_attribute {
??? ?u2 attribute_name_index;
??? ?u4 attribute_length;
??? ?u2 line_number_table_length;
??? ?{? u2 start_pc;??????
??? ??? u2 line_number;??????
??? ?} line_number_table[line_number_table_length];
??? }
attribute_length:10
line_number_table_length:2
start_pc:00 00
line_number:00 01
tart_pc:00 04
line_number:00 03
到此第一個方法結束。
----------------------------------------------------------------------第二個方法開始
access_flags:00 01,public
name_index:00 0D,m1
desc_index:00 0E,(I)I,有一個整數參數,返回一個整數。
00 01:一個attr
00 0B:code
00 00 00 1C:attr_length:28
Code_atrr:28個字節,不分析了和上面的方法相同。
----------------------------------------------------------------------第三個方法
00 02:private
00 0F:m2
00 0A: ()V,無參,返回void
00 01:一個attr
00 0B:code
00 00 00 19:attr_length? 25
接下去的25個字節是Code_atrr,同樣不分析了。
------------------------------------------------------------------
00 01:1個類的attr
00 10:SourceFile
00 00 00 02:len=2
00 11:17,TJ.java
總結
以上是生活随笔為你收集整理的二进制 java Class文件解析实例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深入Java虚拟机:Class文件实例解
- 下一篇: java 测量程序运行时间