您的位置:首页 > 编程语言 > Java开发

《深入理解java虚拟机》之类文件结构

2015-10-14 14:23 549 查看
Java虚拟机语言无关性



Java Class文件结构



1,头4个字节为魔数,用于确定这个文件是否为一个能被虚拟机接受的Class文件,值为:0xCAFEBABE

2,紧接着4个字节,5,6字节是次版本号,7,8字节是主版本号。高版本的JDK能向下兼容以前版本的Class文件,但不能运行以后版本的Class文件,即使文件格式并未发生变化。

3,紧接着主次版本号之后的是常量池入口,1,常量池是Class文件结构中与其他项目关联最多的数据类型,2,占用Class文件空间最大的数据项目之一,3,在Cass文件中第一个出现的表结构数据项目;常量池的前两个字节是一项u2类型的数据,代表常量池容量计数器。这个容量计数是从1开始而不是0,把第0项常量空出来是为了满足 后面某些指向常量池的索引值的数据在特定情况下需要表达“不引用任何一个常量池项目”。

常量池主要两大类常量:字面量和符号引用,字面量类似Java语言的常量概念,如文本字符串,被声明final的常量值等,符号引用属于编译原理方面的概念

三类常量:类和接口的全限定名,字段的名陈和描述符,方法的名称和描述符

Java代码在javac编译时不会连接,而是在虚拟机加载Class文件进行动态连接,即在Class文件中不会保存各个方法和字段的最终内存布局信息

常量池的每一项常量都是一个表,共有11种不同结构的表结构数据,这11种表的共同特点就是,表开始的第一位是一个u1类型的标志位,代表当前这个常量属于哪种常量类型。

4,接着2个字节,代表访问标志,用于识别一些类或接口层次的访问信息

5,接着是类索引,父类索引和接口索引集合;类,父类索引是一个u2(2个字节)类型的数据,索引接口是一组u2类型的数据集合,Class文件由这三项数据来确定这个类的继承关系

类索引用于确定这个类的全限定名

父类索引用于确定这个类的父类的全限定名

接口索引集合用来描述这个类实现哪些接口

根据顺序判断子父类

6,字段表集合,用于描述接口或类中声明的变量

7,方法表集合,如字段表一样,包括发那个问标志,名称索引,描述符索引,属性表集合

8,属性表集合

Code属性,Java程序方法体里面的代码经过javac编译器处理之后,最终变为字节码指令存储在Code属性内。Code属性出现在方法表的属性集合之中,但有特殊,如接口或抽象类中的方法不存在Code属性。

Exceptions属性,列举出方法中可能抛出的受查异常,即方法描述时在throws关键字后面列举的异常。

javap反编译之后的字节码文件

/*
public class Test {
public int getNum(int i) {
return i + 1;
}
} */
public class Test extends java.lang.Object
SourceFile: "Test.java"
minor version: 0
major version: 50
//常量池
Constant pool:
const #1 = class        #2;
const #2 = Asciz        Test;
const #3 = class        #4;
const #4 = Asciz        java/lang/Object;
const #5 = Asciz        <init>;  //实例构造器
const #6 = Asciz        ()V;  //void返回类型
const #7 = Asciz        Code;  //属性表Code属性
const #8 = Method       #3.#9;  //方法特征签名  java/lang/Object."<init>":()V
const #9 = NameAndType  #5:#6;//  方法名称和返回值"<init>":()V
const #10 = Asciz       LineNumberTable;  //属性表源码行号和字节码指令对应表
const #11 = Asciz       LocalVariableTable;  //属性表方法局部变量表
const #12 = Asciz       this;  //Test类实例对象本身
const #13 = Asciz       LTest;;  //对象类型,Test类
const #14 = Asciz       getNum;  //方法名称
const #15 = Asciz       (I)I;  //方法参数列表为一个int类型和返回值为int类型
const #16 = Asciz       i;  //参数名称i
const #17 = Asciz       I;  //参数类型int
const #18 = Asciz       SourceFile;
const #19 = Asciz       Test.java;
//方法表
{
//构造函数(默认构造方法)
public Test();
Code:  //属性表Code属性
Stack=1, Locals=1, Args_size=1
0:   aload_0
1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
4:   return
LineNumberTable:
line 2: 0

LocalVariableTable:  //属性表方法局部变量表
Start  Length  Slot  Name   Signature
0      5      0    this       LTest;

//自定义方法
public int getNum(int);
Code:
Stack=2, Locals=2, Args_size=2
0:   iload_1
1:   iconst_1
2:   iadd
3:   ireturn
LineNumberTable:
line 4: 0

LocalVariableTable:
Start  Length  Slot  Name   Signature
0      4      0    this       LTest;
0      4      1    i       I
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息