深入理解Java虚拟机笔记--6类文件结构

 

6.1概述

1.class文件被编译成与操作系统和指令集无关的格式。

6.2无关性基石

1.sun为不同平台提供不同的虚拟机,但所有虚拟机加载统一格式的字节码文件。

2.class文件有语法和结构的强约束,虚拟机不关心语言,各种编译器将不同的语言编译成统一的字节码文件。

3.java的变量、关键字、运算符都是由字节码命令组合而成,因此字节码命令提供的语义描述能力强于java,也为其他语言提供了其他特性的基础。

 

6.3class类文件结构

1.一个class文件对应一个类或一个接口的定义信息。

2.class文件是一组8位字节位基础的二进制流,各数据项严格排列,中间没有分隔符,8位以上数据存储时采用大端存储(低址存高位)。

3.class文件采用类c结构体的伪结构来存储数据,伪结构有2中类型:

  (1)无符号数:u1,u2,u4表示1,2,4字节无符号数。

  (2)表:由无符号数、表符合而成,class文件本质是一个表。

6.3.1魔数与class文件版本

1.魔数:class文件前4个字节是0xCAFEBABE,唯一的作用就是告诉虚拟机这是一个可以接收的class文件。

 (咖啡宝贝,现在知道java图标的意思了吧)

2.第5,6个字节是次版本号,7,8是主版本号。

3.jdk向下兼容低版本class文件,不向上兼容(即使内容完全一样)。

6.3.2常量池

1.版本号后接常量池索引,常量池索引是从1开始的,其他索引都是从0开始的。

2.常量池索引为0表示不引用任何一个常量池项目。

3.常量池中存放2类常量

  (1)字面量:如文本字符,final变量

  (2)符号引用:1)类和接口的全限定名。2)字段名称与描述。3)方法名称与描述。

4.常量池中每一项都是一张表,每一项开始的一个字节是tag标识,标识了该常量是何种类型。

每种类型对应一张表

 

6.3.3访问标志

1.标识类的信息,是否public,是类或接口,枚举或者注解等。

6.3.4类索引、父类索引、接口索引集合

1.标识类的继承关系,索引指向常量池中常量。

6.3.5字段表集合

1.字段数量描述成员变量数量。

2.访问标志描述成员变量的修饰符private fianl volatile等,简单名、描述符必须引用常量池中变量。

3.名词:

1)全限定名就是带包类名。

2)简单名就是方法或属性的名称。

3)描述符是描述字段类型、方法的参数列表(数量及顺序)及返回值

4.例:pirvate int m,首先描述为private,简单名索引指向常量池,描述符指向常量池。

5.最后是属性表的数量,及属性表索引,例如属性为private static final int m =123; 就需要额外描述。 

6.3.3方法表集合

 1.方法数量描述方法变量的数量。

 2.访问标志描述方法的关键字修饰符如:private fianl volatile等,简单名、描述符必须引用常量池中变量。

 

 

 3.方法描述符:(参数及顺序)返回值,符号见下图,[表示一纬数组,[[表示二维数组

例:void inc() 描述符:()V

  String toString()描述符:()Ljava/lang/String

  int indexOf(char[] source,int sourceOffset,int sourceCount)描述符:([CII)I  

4.最后是属性表的数量,及属性表索引,方法的内容就存在对应常量"Code"中。 

5.java重载不允许参数一样,返回值不同的情况,而虚拟机则允许描述符不同的两个方法存在class文件里。即方法:inc(int i)与方法:String(int i)在java中不可共存,但在class中可以。

 6.3.7属性表集合

1.class文件,字段表,方法表中都含有自己的属性。

2.属性表的结构

(共性)nameindex指向常量池,length表示属性数量,(个性)info为每一个不同属性的表结构

3.code属性:

1)java代码编译成字节码指令后会存在code属性内

2)不是所有函数都有code属性()interface abstractclass

3)属性表结构:

 

4)attribute_name_index 指向常量池中CONSTANT_UTF8_info型常量的索引,固定值"Code"

5)max_stack操作数栈的最大深度,虚拟机运行时根据这个分配栈帧中的操作栈深度

6)max_locals代表局部变量表所需的存储空间,单位slot(虚拟机的最小存储空间,不超过32位的int,short等占1个slot),方法参数(包括隐藏参数this)、异常处理参数catch(定义的异常)、方法体中变量都需要在局部变量中存储,这些slot会动态回收重用。

7)code_length字节码指令的长度,一个指令占1k

8)class中2个重要部分:code和metadata(字段、类、方法)

9)实例方法中第一个隐藏参数为this

10)字节码指令后是异常处理表

11)在startpc-endpc间(字节码偏移量)出现catchtype及其子类时跳转至handlerpc处理,catchtype为0

4.Exception属性列举checked exception

name 、index指向常量池,number表示方法可能抛出exception的数量

4.LineNumberTable属性栈帧中局部变量表的变量和源码变量的对应关系

5.sourceFile属性记录源码文件名称

6.constantValue使虚拟机自动为静态变量赋值

 1)非static变量赋值的时机为实例构造器中

 2)static变量如果为基础数据类型或String且被final修饰则生成constantValue属性进行初始化,否则在类初始化方法中进行初始化

7.innerClass内部类属性,记录内部类、外部类、访问标识

8.deprecated标识类、字段、方法是否不在被使用。synthetic标识方法、字段是否由源码产生

9.stackMapTable被检查验证器使用

10.signature记录泛型签名信息,因为java是假泛型运行期间会擦出泛型信息,反射则拿不到泛型信息,属性为类属性表示类签名,为方法属性表示方法类型签名,为字段属性为字段类型签名。

11.bootstrastrapMethods

posted @ 2018-09-05 22:27  扶不起的刘阿斗  阅读(144)  评论(0编辑  收藏  举报