public class TestClass {
private int m;
public int inc() {
return m+1;
}
}
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];
}
public class com.enjoy.learn.core.oop.method.TestClass
minor version: 0
major version: 52
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #3 // com/enjoy/learn/core/oop/method/TestClass
super_class: #4 // java/lang/Object
interfaces: 0, fields: 1, methods: 2, attributes: 1
Constant pool:
#1 = Methodref #4.#18 // java/lang/Object."<init>":()V
#2 = Fieldref #3.#19 // com/enjoy/learn/core/oop/method/TestClass.m:I
#3 = Class #20 // com/enjoy/learn/core/oop/method/TestClass
#4 = Class #21 // java/lang/Object
#5 = Utf8 m
#6 = Utf8 I
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 Lcom/enjoy/learn/core/oop/method/TestClass;
#14 = Utf8 inc
#15 = Utf8 ()I
#16 = Utf8 SourceFile
#17 = Utf8 TestClass.java
#18 = NameAndType #7:#8 // "<init>":()V
#19 = NameAndType #5:#6 // m:I
#20 = Utf8 com/enjoy/learn/core/oop/method/TestClass
#21 = Utf8 java/lang/Object
{
public com.enjoy.learn.core.oop.method.TestClass();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 10: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/enjoy/learn/core/oop/method/TestClass;
public int inc();
descriptor: ()I
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: getfield #2 // Field m:I
4: iconst_1
5: iadd
6: ireturn
LineNumberTable:
line 13: 0
LocalVariableTable:
Start Length Slot Name Signature
0 7 0 this Lcom/enjoy/learn/core/oop/method/TestClass;
}
SourceFile: "TestClass.java"
1.u4 magic;
ca fe ba be
2.u2 minor_version;
00 00
3.u2 major_version;
00 34
也即版本号为十进制的52
4.u2 constant_pool_count;
00 16
也即十进制的22,由于常量池保留了0项,所以常量池的项目范围是1-21.
5.cp_info constant_pool[constant_pool_count-1];
cp_info {
u1 tag;
u1 info[];
}
info的大小根据tag的不同而不同,其中tag的种类如下:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
CONSTANT_Integer_info {
u1 tag;
u4 bytes; //高位在前存储的int值
}
CONSTANT_Float_info {
u1 tag;
u4 bytes;
}
CONSTANT_Long_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
CONSTANT_Double_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
CONSTANT_Class_info {
u1 tag;
u2 name_index; //指向常量池的索引,代表类的全限定名Utf8类型常量
}
CONSTANT_String_info {
u1 tag;
u2 string_index;
}
CONSTANT_Fieldref_info {
u1 tag;
u2 class_index; //类或接口的索引Class_info
u2 name_and_type_index; //字段描述符的索引
}
CONSTANT_Methodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_InterfaceMethodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_NameAndType_info {
u1 tag;
u2 name_index;
u2 descriptor_index;
}
CONSTANT_MethodHandle_info {
u1 tag;
u1 reference_kind;
u2 reference_index;
}
CONSTANT_MethodType_info {
u1 tag;
u2 descriptor_index;
}
CONSTANT_InvokeDynamic_info {
u1 tag;
u2 bootstrap_method_attr_index;
u2 name_and_type_index;
}
阅读class文件:
1)0a 代表Methodref,后面u2 class_index; u2 name_and_type_index;
00 04 java/lang/Object
00 12 (十进制18)<init> ()V
2)09 代表Fieldref,后面u2 class_index; u2 name_and_type_index;
00 03 com/enjoy/learn/core/oop/method/TestClass
00 13 (十进制19)m I
3)07代表Class,后面u2 name_index
00 14 (十进制20)com/enjoy/learn/core/oop/method/TestClass
4)07代表Class,后面u2 name_index
00 15(十进制21)
java/lang/Object
5)01代表utf8, u2 length; u1 bytes[length];
00 01表示长度为1
6d m
6)01代表utf8, u2 length; u1 bytes[length];
00 01表示长度为1
49 I
7)01代表utf8, u2 length; u1 bytes[length];
00 06长度为6
3c 69 6e 69 74 3e <init>
8)01代表utf8, u2 length; u1 bytes[length];
00 03长度为3
28 29 56 ()V
9)01代表utf8, u2 length; u1 bytes[length];
00 04长度为4
43 6f 64 65 Code
10)01代表utf8, u2 length; u1 bytes[length];
00 0f长度为15
4c 69 6e 65 4e 75 6d 62
65 72 54 61 62 6c 65 LineNumberTable
11)01代表utf8, u2 length; u1 bytes[length];
00 12长度为18
4c 6f 63 61 6c 56 61 72
69 61 62 6c 65 54 61 62
6c 65 LocalVariableTable
12)01代表utf8, u2 length; u1 bytes[length];
00 04长度为4
74 68 69 73 this
13)01代表utf8, u2 length; u1 bytes[length];
00 2b长度为43
4c 63 6f 6d 2f 65 6e
6a 6f 79 2f 6c 65 61 72 6e 2f 63 6f 72 65 2f 6f
6f 70 2f 6d 65 74 68 6f 64 2f 54 65 73 74 43 6c
61 73 73 3b Lcom/enjoy/learn/core/oop/method/TestClass
14)01代表utf8, u2 length; u1 bytes[length];
00 03长度为3
69 6e 63 代表 inc
15)01代表utf8, u2 length; u1 bytes[length];
00 03长度为3
28 29 49 代表 ()I
16)01代表utf8, u2 length; u1 bytes[length];
00 0a长度为10
53 6f 75 72 63 65 46 69 6c 65 SourceFile
17)01代表utf8, u2 length; u1 bytes[length];
00 0e长度为14
54 65 73 74 43 6c 61 73 73 2e 6a 61 76 61 TestClass.java
18)0c代表NameAndType, u2 name_index;u2 descriptor_index;
00 07 <init>
00 08 ()V
19)0c代表NameAndType, u2 name_index;u2 descriptor_index;
00 05 m
00 06 I
20)01代表utf8, u2 length; u1 bytes[length];
00 29长度为41
63 6f 6d 2f 65
6e 6a 6f 79 2f 6c 65 61 72 6e 2f 63 6f 72 65 2f
6f 6f 70 2f 6d 65 74 68 6f 64 2f 54 65 73 74 43
6c 61 73 73 com/enjoy/learn/core/oop/method/TestClass
21)01代表utf8, u2 length; u1 bytes[length];
00 10长度为16
6a 61 76 61 2f 6c 61 6e 67
2f 4f 62 6a 65 63 74 java/lang/Object
javap -v 翻译过后
Constant pool:
#1 = Methodref #4.#18 // java/lang/Object."<init>":()V
#2 = Fieldref #3.#19 // com/enjoy/learn/core/oop/method/TestClass.m:I
#3 = Class #20 // com/enjoy/learn/core/oop/method/TestClass
#4 = Class #21 // java/lang/Object
#5 = Utf8 m
#6 = Utf8 I
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 Lcom/enjoy/learn/core/oop/method/TestClass;
#14 = Utf8 inc
#15 = Utf8 ()I
#16 = Utf8 SourceFile
#17 = Utf8 TestClass.java
#18 = NameAndType #7:#8 // "<init>":()V
#19 = NameAndType #5:#6 // m:I
#20 = Utf8 com/enjoy/learn/core/oop/method/TestClass
#21 = Utf8 java/lang/Object
6.u2 access_flags;
00 21
表示ACC_PUBLIC ACC_SUPER
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
7.u2 this_class;
00 03 常量池 #3 = Class #20 // com/enjoy/learn/core/oop/method/TestClass
类索引用于确定该类的全限定名
this_class: #3 // com/enjoy/learn/core/oop/method/TestClass
8.u2 super_class;
00 04 常量池#4 = Class #21 // java/lang/Object
确定父类的全限定名
super_class: #4 // java/lang/Object
9.u2 interfaces_count;
00 00 表示该类没有实现任何接口
10.u2 interfaces[interfaces_count];
确定该类实现了哪些接口
interfaces: 0
11.u2 fields_count;
00 01
12.field_info fields[fields_count];
field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
00 02 access_flags
表示private
00 05 name_index (常量池索引)字段的简单名称
查看#5 = Utf8 m
00 06 descriptor_index (常量池索引)字段描述符
查看 #6 = Utf8 I
00 00 attributes_count
如果声明改为"final static int m = 123;",则有一个ConstantValue属性,其值指向常量123.
由上可知字段定义为:private int m;
注意事项:
1)不会出现超类或父类中继承而来的字段
2)可能会列出原本不存在的字段:例如内部类对外部类的访问
13.u2 methods_count;
00 02 有两个方法
14.method_info methods[methods_count];
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
00 01 access_flags
ACC_PUBLIC
00 07 name_index
代表 #7 = Utf8 <init>
00 08 descriptor_index
代表 #8 = Utf8 ()V
00 01 attributes_count 有一个属性
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
00 09 attribute_name_index
代表#9 = Utf8 Code
代表此属性是方法的字节码描述
00 00 00 2f attribute_length(长度为47)
Code属性表:
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 01 max_stack
00 01 max_locals
00 00 00 05 code_length
2a //aload_0 将第0个引用类型本地变量推送至栈顶
b7 // invokespecial 以栈顶的引用类型的对象作为方法接收者,调用此对象的实例构造方法、private方法或者其父类方法。该方法有一个u2类型参数,指向常量池中的CONSTANT_Methodref_info常量,即方法的符号引用。
00 01 //方法的符号引用#1 = Methodref #4.#18 // java/lang/Object."<init>":()V
b1 //return 从当前方法返回void
00 00 exception_table_length
exception_table[exception_table_length]为空
00 02 attributes_count 两个大小
00 0a attribute_name_index //#10 = Utf8 LineNumberTable
00 00 00 06 attribute_length
00 01 line_number_table_length
00 00 start_pc
00 0a line_number
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 0b attribute_name_index//#11 = Utf8 LocalVariableTable
00 00 00 0c attribute_length
00 01 local_variable_table_length
00 00 start_pc
00 05 length
00 0c name_index ——> this
00 0d descriptor_index ——> #13 = Utf8 Lcom/enjoy/learn/core/oop/method/TestClass;
00 00 index
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];
}
public com.enjoy.learn.core.oop.method.TestClass();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 10: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/enjoy/learn/core/oop/method/TestClass;
如下为第二个方法:
00 01 access_flags
ACC_PUBLIC
00 0e name_index
代表#14 = Utf8 inc
00 0f descriptor_index
代表#15 = Utf8 ()I
00 01 attributes_count
00 09 attribute_name_index
代表#9 = Utf8 Code
代表此属性是方法的字节码描述
00 00 00 31 attribute_length
public int inc();
descriptor: ()I
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: getfield #2 // Field m:I
4: iconst_1
5: iadd
6: ireturn
LineNumberTable:
line 13: 0
LocalVariableTable:
Start Length Slot Name Signature
0 7 0 this Lcom/enjoy/learn/core/oop/method/TestClass;
注意:
1)如果方法未被重写,父类方法不会出现
2)可能会出现由编译器自动添加的方法:类构造器<cinit>和实例构造器<init>
3)任何实例方法中,都可以通过this关键字访问到此方法所属的对象。实例方法的局部变量表中至少会存在this,第一个Slot位置给this,方法参数值从1开始。static方法从0开始。
15.u2 attributes_count;
00 01
16.attribute_info attributes[attributes_count];
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
00 10 attribute_name_index
代表 #16 = Utf8 SourceFile
00 00 00 02 attribute_length
00 11
代表 #17 = Utf8 TestClass.java
SourceFile: "TestClass.java"
属性表出现在:
1)Class文件
RuntimeVisibleTypeAnnotations
RuntimeInviisibleTypeAnnotations —— 三者+Code属性均可用
Deprecated——三者均可用
Signature——三者均可用 记录泛型签名信息,为了避免擦除后信息丢失
Synthetic —— 三者均可 编译器自动生成
RuntimeVisibleAnnotations—— 三者均可用 运行时可见,反射调用
RuntimeInvisivleAnnotations——运行时不可见
EnclosingMethod——局部类或匿名类的外围方法
InnerClasses——内部类列表
SourceFile——源文件名称
SourceDebugExtension——存储额外的调试信息
BootstrapMethods——用于保存invokedynamic指令引用的引导方法限定符
2)字段表
ConstantValue——final字段
3)方法表
Code——字节码指令
LineNumberTable——Code属性 源码行号
LocalVariableTable——Code属性 局部变量
LocalVariableTypeTable——使用特征签名代替描述符,描述泛型 参数化类型
StackMapTable——局部变量和操作数栈所需类型是否匹配
Exceptions——方法抛出的异常
RuntimeVisibleParameterAnnotations——方法参数注解
RuntimeInvisibleParameterAnnotations——方法参数注解
AnnotationDefault——默认值
MethodParameters——
按照新增属性的前后顺序: