1、Code属性表结构:
数据类型 | 名称 | 数量 |
---|---|---|
u2 | attribute_name_index | 1 |
u4 | attribute_length | 1 |
u2 | max_stack | 1 |
u2 | max_locals | 1 |
u4 | code_length | 1 |
u1 | code | code_length |
u2 | exception_table_length | 1 |
exception_info | exception_table | exception_table_length |
u2 | attribute_count | 1 |
attribute_info | attributes | attribute_count |
2、看二进制实例:
max_stack操作数栈operand Stacks)深度的最大值,虚拟机运行时根据此分配栈帧(stack frame),max_locals局部变量表所需的空间,Slot为单位,对于boolean,byte,char,short,int,float,returnAddress等长度不超过32位的数据类型,每个数据类型占一个Slot。code为字节码指令
属性
26 0x105 0x0009 0000 002F 0001 0001 0000 0005 2AB7 000A B1 其中0x0009指向属性名称的索引,0x0000 002F属性值长度(为属性表长度-6,因为名称和属性长度共占6字节),
0x0001为max_stack, 0x0001为max_locals, 0x0000 0005为长度字节码指令长度,2AB7 000A B1
Code属性是Class文件中最重要的属性,如果把JAVA程序中的信息分为代码(Code,方法体中的代码)和元数据(Metadata,类、字段、方法定义及其他信息)两部分,在整个class文件中,Code属性用于描述代码,所有的其他数据项目都用于描述元数据。
3、接着查看“2AB7 000A B1”:
- 0x2A的指令为aload_0:将第0个Slot中为reference类型的本地变量放到操作数栈顶;
- 0xB7为指令invokespecial,以栈顶的reference类型数据指向的对象作为方法的接收者,调用此对象的
- 实例构造器方法;
- private方法
- 父类方法
接着一个u2的参数说明具体调用哪个方法
- 0x000A ,为invokespecial的参数,查常量池得“< init>”
- 0xB1,为指令return,返回方法,返回类型为void
4、 通过javap查看的信息:
{
public jvm.loadingclass.TestClass();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #10 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Ljvm/loadingclass/TestClass;
public int inc();
descriptor: ()I
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: getfield #18 // Field m:I
4: iconst_1
5: iadd
6: ireturn
LineNumberTable:
line 6: 0
LocalVariableTable:
Start Length Slot Name Signature
0 7 0 this Ljvm/loadingclass/TestClass;
}
- 注意到Args_size =1,在< init>()实例构造器和inc()方法中并没有参数,也没有定义局部变量,但是Locals=1。在任何实例方法中,都可以通过this来获得当前对象的引用,实际上是javac编译器编译时,每个实例方法都会传入this这个参数,导致所有的实例方法的局部变量表都会有this,所以我们看到Args_size=1,Locals=1。如果inc为static,那么Args_size=0,Locals=0
注:this代表调用这个方法的对象引用
5、异常表的结构:
类型 | 名称 | 数量 |
---|---|---|
u2 | start_pc | 1 |
u2 | end_pc | 1 |
u2 | handler_ | 1 |
u2 | catch_type | 1 |
public class TestClass {
public int inc() {
int x ;
try{
x = 1;
return x;
}catch(Exception e){
x = 2;
}finally{
x = 3;
}
return 0;
}
}
public int inc();
descriptor: ()I
flags: ACC_PUBLIC
Code:
stack=1, locals=5, args_size=1
0: iconst_1
1: istore_1
2: iload_1
3: istore 4
5: iconst_3
6: istore_1
7: iload 4
9: ireturn
10: astore_2
11: iconst_2
12: istore_1
13: iconst_3
14: istore_1
15: goto 23
18: astore_3
19: iconst_3
20: istore_1
21: aload_3
22: athrow
23: iconst_0
24: ireturn
Exception table:
from to target type
0 5 10 Class java/lang/Exception
0 5 18 any
10 13 18 any
(这里之后书上本章大多是理论说明,先不细看,学习后面的类加载机制,再往回来细看)