Java的class文件結(jié)構(gòu)

在《深入理解java虛擬機(jī)》一書(shū)第6章講到了java的類(lèi)文件,并且詳情介紹了java的class文件的內(nèi)容。但是,真的,我覺(jué)著很多人看不懂,看的一臉懵逼啊,其實(shí)這一章的內(nèi)容上絕對(duì)是沒(méi)有問(wèn)題的,但是組織結(jié)構(gòu)實(shí)在是不合理。筆者結(jié)合java虛擬機(jī)規(guī)范給大家整理一下我們的認(rèn)識(shí)。(https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html)。

首先我們來(lái)看class文件的整體結(jié)構(gòu):
ClassFile {
1 u4 magic;
2 u2 minor_version;
3 u2 major_version;
4 u2 constant_pool_count;
5 cp_info constant_pool[constant_pool_count-1];
6 u2 access_flags;
7 u2 this_class;
8 u2 super_class;
9 u2 interfaces_count;
10 u2 interfaces[interfaces_count];
11 u2 fields_count;
12 field_info fields[fields_count];
13 u2 methods_count;
14 method_info methods[methods_count];
15 u2 attributes_count;
16 attribute_info attributes[attributes_count];
}
u1,u2,u4表示1個(gè)字節(jié),2個(gè)字節(jié),4個(gè)字節(jié)。一共16個(gè)內(nèi)容,總結(jié)一下

第1行,magic,魔數(shù),這個(gè)是都是固定的,在下文的class文件你也會(huì)看到,
四個(gè)字節(jié),都是:CA FE BA BE

第2,3行,表示的是版本

第4,5行表示常量池

第6行表示這個(gè)類(lèi)的訪問(wèn)表示(public,private等)
第7行,類(lèi)的名字
第8行,父類(lèi)的名字
第9,10行,實(shí)現(xiàn)的接口,如果沒(méi)有,那么第10行的內(nèi)容為空。下文會(huì)看到

第11,12行,字段的信息

第13,14行方法的信息

第15,16行屬性的信息

我們需要關(guān)注的其實(shí)主要從4行以后,主要就是常量池、類(lèi)繼承關(guān)系和實(shí)現(xiàn)接口,類(lèi)中的字段方法,還有就是其他的屬性。

書(shū)中給了一段代碼,我自己實(shí)現(xiàn)如下(除了包名其他都和書(shū)中一樣)

package vitualmachine;

public class TestClass {
private int m;
public int inc(){
return m+1;
}
}
這些代碼編譯后的class文件如下:

CA FE BA BE 00 00 00 33 00 16 07 00 02 01 00 17
76 69 74 75 61 6C 6D 61 63 68 69 6E 65 2F 54 65
73 74 43 6C 61 73 73 07 00 04 01 00 10 6A 61 76
61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 01 00 01
6D 01 00 01 49 01 00 06 3C 69 6E 69 74 3E 01 00
03 28 29 56 01 00 04 43 6F 64 65 0A 00 03 00 0B
0C 00 07 00 08 01 00 0F 4C 69 6E 65 4E 75 6D 62
65 72 54 61 62 6C 65 01 00 12 4C 6F 63 61 6C 56
61 72 69 61 62 6C 65 54 61 62 6C 65 01 00 04 74
68 69 73 01 00 19 4C 76 69 74 75 61 6C 6D 61 63
68 69 6E 65 2F 54 65 73 74 43 6C 61 73 73 3B 01
00 03 69 6E 63 01 00 03 28 29 49 09 00 01 00 13
0C 00 05 00 06 01 00 0A 53 6F 75 72 63 65 46 69
6C 65 01 00 0E 54 65 73 74 43 6C 61 73 73 2E 6A
61 76 61 00 21 00 01 00 03 00 00 00 01 00 02 00
05 00 06 00 00 00 02 00 01 00 07 00 08 00 01 00
09 00 00 00 2F 00 01 00 01 00 00 00 05 2A B7 00
0A B1 00 00 00 02 00 0C 00 00 00 06 00 01 00 00
00 03 00 0D 00 00 00 0C 00 01 00 00 00 05 00 0E
00 0F 00 00 00 01 00 10 00 11 00 01 00 09 00 00
00 31 00 02 00 01 00 00 00 07 2A B4 00 12 04 60
AC 00 00 00 02 00 0C 00 00 00 06 00 01 00 00 00
06 00 0D 00 00 00 0C 00 01 00 00 00 07 00 0E 00
0F 00 00 00 01 00 14 00 00 00 02 00 15

下面我們拆解這個(gè)class文件:
CA FE BA BE 魔數(shù)
00 00 00 33版本號(hào)
00 16 常量池個(gè)數(shù),21個(gè)
因?yàn)槌A砍氐男蛱?hào)從1開(kāi)始,0空出來(lái)了,所有0X16中有一個(gè)是空出來(lái)的,所以只有21個(gè)了。
使用javap反編譯之后看到所有21個(gè)常量:前面是序號(hào),后面介紹的屬性或者其他信息的index對(duì)應(yīng)的數(shù)值就是這個(gè)標(biāo)號(hào),注意進(jìn)制轉(zhuǎn)換。
Constant pool:

1 = Class #2 // vitualmachine/TestClass

2 = Utf8 vitualmachine/TestClass

3 = Class #4 // java/lang/Object

4 = Utf8 java/lang/Object

5 = Utf8 m

6 = Utf8 I

7 = Utf8 <init>

8 = Utf8 ()V

9 = Utf8 Code

10 = Methodref #3.#11 // java/lang/Object."<init>":()V

11 = NameAndType #7:#8 // "<init>":()V

12 = Utf8 LineNumberTable

13 = Utf8 LocalVariableTable

14 = Utf8 this

15 = Utf8 Lvitualmachine/TestClass;

16 = Utf8 inc

17 = Utf8 ()I

18 = Fieldref #1.#19 // vitualmachine/TestClass.m:I

19 = NameAndType #5:#6 // m:I

20 = Utf8 SourceFile

21 = Utf8 TestClass.java

下面開(kāi)始進(jìn)入每個(gè)具體的常量:

每個(gè)常量的信息如下,一個(gè)字節(jié)表示類(lèi)別,一個(gè)字節(jié)數(shù)組表示信息,這個(gè)字節(jié)數(shù)組的結(jié)構(gòu)隨第一個(gè)字節(jié)類(lèi)別變化,不同的類(lèi)型結(jié)構(gòu)不同。
cp_info {
u1 tag;
u1 info[];
}

Constant Type Value
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
CONSTANT_MethodHandle 15
CONSTANT_MethodType 16
CONSTANT_InvokeDynamic 18

第一個(gè)常量 07 00 02
07表示類(lèi)常量,結(jié)構(gòu)如下:
CONSTANT_Class_info {
u1 tag;
u2 name_index;
}
后面的 00 02 表示索引
第二個(gè)常量,01 00 17
76 69 74 75 61 6C 6D 61 63 68 69 6E 65 2F 54 65
73 74 43 6C 61 73 73
01表示是UTF8,長(zhǎng)度是17,后面是具體的內(nèi)容,對(duì)應(yīng)23(0X17)個(gè)字字母:
vitualmachine/TestClass
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}

第三個(gè)常量,類(lèi)信息 07 00 04
第四個(gè)常量,UTF-8: 01 00 10
6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74
第五個(gè),UTF-8: 01 00 01 6D
第6個(gè): 01 00 01 49
第7個(gè): 01 00 06 3C 69 6E 69 74 3E
第8個(gè):01 00 03 28 29 56
第9個(gè):01 00 04 43 6F 64 65
第10個(gè):0A 00 03 00 0B 0C 00
第11個(gè):07 00 08
第12個(gè):01 00 0F 4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65
第13個(gè):01 00 12 4C 6F 63 61 6C 56 61 72 69 61 62 6C 65 54 61 62 6C 65
第14個(gè):01 00 04 74 68 69 73
第15個(gè):01 00 19 4C 76 69 74 75 61 6C 6D 61 63 68 69 6E 65 2F 54 65 73 74 43 6C 61 73 73 3B
第16個(gè):01 00 03 69 6E 63
第17個(gè):01 00 03 28 29 49

CONSTANT_Fieldref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
第18個(gè):09 00 01 00 13
CONSTANT_NameAndType_info {
u1 tag;
u2 name_index;
u2 descriptor_index;
}
第19個(gè):0C 00 05 00 06
第20個(gè):01 00 0A 53 6F 75 72 63 65 46 69 6C 65
第21個(gè):01 00 0E 54 65 73 74 43 6C 61 73 73 2E 6A 61 76 61

常量池結(jié)束之后是如下:

u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];

00 21 下面的組合 PUBLIC 和SUPER
Flag Name Value Interpretation
ACC_PUBLIC 0x0001 Declared public; may be accessed from outside its package.
ACC_FINAL 0x0010 Declared final; no subclasses allowed.
ACC_SUPER 0x0020 Treat superclass methods specially when invoked by the invokespecial instruction.
ACC_INTERFACE 0x0200 Is an interface, not a class.
ACC_ABSTRACT 0x0400 Declared abstract; must not be instantiated.
ACC_SYNTHETIC 0x1000 Declared synthetic; not present in the source code.
ACC_ANNOTATION 0x2000 Declared as an annotation type.
ACC_ENUM 0x4000 Declared as an enum type.

00 01 這個(gè)類(lèi),第1個(gè)常量
00 03 父類(lèi),第3個(gè)常量
00 00 接口數(shù)0,所以interfaces[interfaces_count];就不表示,空出來(lái)了。

接著是屬性

u2 fields_count;
field_info fields[fields_count];
只有一個(gè)字段:
field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}

00 01 00 02 00 05 00 06 00 00
屬性值是0,所以attribute_info 沒(méi)有表示。

接下來(lái)是方法

u2             methods_count;
method_info    methods[methods_count];

兩個(gè)方法
00 02

第一個(gè)方法

method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
00 01 00 07 00 08 00 01 一個(gè)屬性:
屬性索引是09,對(duì)應(yīng)Code
00 09
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];
}

00 00 00 2F 長(zhǎng)度
00 01 最大棧
00 01 最大locals
00 00 00 05 代碼長(zhǎng)度5個(gè)
2A B7 00 0A B1 代碼
00 00 異常, 沒(méi)有
00 02 屬性?xún)蓚€(gè)
第一個(gè)屬性 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];
}
00 0C 索引
00 00 00 06長(zhǎng)度是6
00 01 00 00 00 03

第2個(gè)屬性:LocalVariableTable
LocalVariableTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 local_variable_table_length;
{ u2 start_pc;
u2 length;
u2 name_index;
u2 descriptor_index;
u2 index;
} local_variable_table[local_variable_table_length];
}
00 0D 索引
00 00 00 0C 長(zhǎng)度 12
00 01 00 00 00 05 00 0E 00 0F 00 00

第二個(gè)方法:

method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
00 01 表示public
00 10 第16個(gè)常量
00 11
00 01 一個(gè)屬性,和第一個(gè)方法一樣都是Code
00 09
00 00 00 31 長(zhǎng)度49
00 02 00 01 00 00 00 07 2A B4 00 12 04 60 AC 00
00 00 02 00 0C 00 00 00 06 00 01 00 00 00 06 00
0D 00 00 00 0C 00 01 00 00 00 07 00 0E 00 0F 00
00

最后剩下的,其他屬性

u2 attributes_count;
attribute_info attributes[attributes_count];

00 01 長(zhǎng)度是1
00 14 第14個(gè)常量 sourcefile
SourceFile_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 sourcefile_index;
}
00 00 00 02 長(zhǎng)度
00 15 索引對(duì)應(yīng)21個(gè),就是最后一個(gè)常量TestClass.java
到處結(jié)束。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • magic num : ca fe ba be minor version: 0...
    數(shù)碼資訊站閱讀 623評(píng)論 0 50
  • 1.流程 創(chuàng)建 HelloWorld.java代碼如下package jvm; /** * @author ...
    RunAlgorithm閱讀 1,370評(píng)論 4 6
  • 益達(dá): 你好,來(lái)信已收到。 收到來(lái)信的時(shí)候,很高興。因?yàn)槟愀嬖V我,你加入了一個(gè)22天的行動(dòng)營(yíng)。 你說(shuō)這個(gè)行動(dòng)營(yíng),可...
    城市的知了閱讀 272評(píng)論 9 8
  • 看到這張圖我仔細(xì)想了想,我好像也是一個(gè)生性淡薄的人。明明昨天還覺(jué)得小說(shuō)不看完不可,微博有魔力就像吸毒一樣?,F(xiàn)在忽然...
    莫干山的小狐貍閱讀 223評(píng)論 0 0
  • 朋友圈,微信好友己經(jīng)達(dá)到了上限,一個(gè)月前,就想刪除僵尸粉,直到現(xiàn)在,一天推一天,由于僵尸粉占據(jù)位置,好多朋...
    夢(mèng)之海L閱讀 471評(píng)論 0 0