JAVA类文件Class内部结构

JAVA的平台无关性怎么实现的?

字节码是构成平台无关系的基石。JAVA在刚刚诞生时就提出"Write Once, Run Anywhere",将编写的程序编译成所有平台都可以使用的程序存储格式:字节码。JAVA虚拟机不和任何语言绑定,它只与"Class文件"这种二进制文件格式相关联。任意一门功能性语言都可以把程序代码编译成Class文件被JAVA虚拟机接受,如Scala、Clojure、Groovy、JRuby、Jython等。

JAVA的类文件结构?

Class文件格式采用一种伪结构来存储数据,包括两种数据类型:无符号数和表。整个Class文件本质上就是一张表:

类型 名称 数量
u4 magic 1
u2 minor_version 1
u2 major_version 1
u2 constant_pool_count 1
cp_info constant_pool constant_pool_count-1
u2 access_flags 1
u2 this_class 1
u2 super_class 1
u2 interfaces_count 1
u2 interfaces interfaces_count
u2 fields_count 1
field_info fields fields_count
u2 methods_count 1
method_info methods methods_count
u2 attributes_count 1
attribute_info attributes attributes_count

从上到下分析:

魔数与版本

开头4个字节(u4)称为魔数(Magic Number),它唯一作用是表明这是一个能被虚拟机接受的Class文件。这四个字节用16进制来表示是0xCAFEBABE。
紧接着的u2两个字节是次版本号,再后面u2两个字节是主版本号。

常量池

由于常量池中常量的数量是不固定的,所以先用u2标明容量(constant_pool_count) 。如果是0x0016,则表明有21个常量(1*16+6-1)。 只有常量池的容量是从1开始计数的,其他集合类型都是从0开始计数。
常量池存放两大类常量:字面量和符号引用。字面量如文本字符串、声明为final的常量值等。符号引用包括:类和接口的全限定名、字段的名称和描述符、方法的名称和描述符。符号引用不经过运行期转换无法转为真正的内存地址。每个常量都有一个tag位(u1)来标明常量的类型,如整型字面量、浮点型字面量、类和接口的符号引用、字段或方法的符号引用等。可用javap命令来输出Class文件的字节码。

javap -verbose TestClass

访问标志

access_flags为两个字节,标明是否为类或接口,是否为public、abstract、final等。

类索引父类索引与接口索引集合

this_class(类索引)、super_class(父类索引)各自指向一个类型为CONSTANT_Class_info的类描述符常量,通过其索引值name_index可以找到常量池中的全限定名。

字段表集合

字段表(field_info)包括类和接口中声明的变量。
变量会由各种修饰符来定义:public/private/protected、static、final、volatile、transient、int/long/float、是数组还是对象等等。
每个字段由access_flags、name_index、descriptor_index来表示,即字段修饰符、简单名称索引和描述符索引。简单名称可理解为变量名,实际值存在常量池中,这里只维护引用。描述符用大写字母表示:I代表int,B代表byte,J代表long,Z代表boolean、L代表对象类型等等。

方法表集合

方法表跟字段表相似,多了一个属性表集合。

属性表集合

在Class文件、字段表、方法表中都可以携带属性表。
如方法表中的Code、字段表中的ConstantValue、Code属性中的LineNumberTable、LocalVariableTable、StackMapTable。
属性的名称在常量池中,由attribute_name_index引用。
这里只介绍Code属性:除了接口或抽象类中的方法,其他的方法体编译后的字节码指令存储在Code属性内。包括属性名索引、属性长度、操作数栈最大深度、局部变量表所需空间、源代码生成的字节码指令、异常表等。

Class文件的基础单位是什么?

8位字节的二进制流。如果超出8位,高位在前(Big-Endian)。

方法里的JAVA代码编译成字节码后存放在哪里?

Code属性里面。

子类方法表会不会有父类的方法?

不会,除非子类重写(Override)了父类方法。

参考资料

《深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)》 周志明 著
http://icyfenix.iteye.com

猜你喜欢

转载自blog.csdn.net/weixin_42628594/article/details/85039453