Class类文件的结构
来源:互联网 发布:jdbc连接db2数据库 编辑:程序博客网 时间:2024/05/21 09:29
JAVA实现平台无关性的基础是虚拟机和字节码存储格式,使用Java编译器可以把Java代码编译为存储字节码的Class文件,使用JRuby等其他语言的编译器一样可以把程序代码编译成Class文件,虚拟机并不关心Class的来源是什么语言,只要它符合Class文件应有的结构就可以在Java虚拟机中运行。
Java语言中的各种变量、关键字和运算符号的语义最终都是由多条字节码命令组合而成的,因此字节码命令所能提供的语义描述能力肯定比Java语言本身更强大。Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在Class文件之中,中间没有添加任何分隔符,这使得整个Class文件存储的内容几乎全部都是程序运行的必要数据,没有空隙。当遇到需要占用8位字节以上空间的数据项时,则会按照高位在前的方式分割成若干个8位字节进行存储。
根据Java虚拟机规范的规定,Class文件格式采用一种类似于C语言结构体的伪结构表示。与C语言结构体的域不同,连续的项Java Class文件中顺序存储,不进行填充或者对齐。在《JVM Specification》中式这样定义Class文件的结构:
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]; }
接下来我们一起看看这个表中各个数据项的具体含义。使用下面的测试类进行详细说明:
package com.igood;public class TestClass {private int member;//int类型字段public static String HOME_URL="http://www.baidu.com";//static字符字段public final float PI = 3.14159F;//final字段//构造函数public TestClass(){}//getMember函数public int getMember() {return member;}}编译完成的类文件如下:
1、magic
每个Class文件的头4个字节称为魔数,它的唯一作用是用于确定这个文件是否为一个能被虚拟机接受的Class文件,它的值为0xCAFEBABE。
2、minor_version和major_version
紧接着魔数的4个字节存储的是Class文件的版本号:第5、6个字节是次版本号(minor_version),第7、8字节是主版本号(major_version)。Java的版本号从45开始。
3、常量池
紧接着主次版本号之后的是常量池入口,由于常量池中常量的数量是不固定的,所以再常量池的入口需要放置一项u2的类型的数据,代表常量池容量计数值(constant_pool_count),这个容量计数是从1而不是从0开始的。常量池(constant_pool)存储了诸如符号常量、final常量值、基本数据类型的字面值等内容。在jVM的头文件jvm/vmcommon/h/pool.h中,有以下对常量池项类型的定义:
#define CONSTANT_Utf8 1 //UTF-8编码的Unicode字符串#define CONSTANT_Integer 3 //int类型的字面值#define CONSTANT_Float 4 //float类型的字面值#define CONSTANT_Long 5 //long类型的字面值#define CONSTANT_Double 6 //double类型的字面值#define CONSTANT_Class 7 //对一个类或接口的符号引用#define CONSTANT_String 8 //String类型字面值的引用#define CONSTANT_Fieldref 9 //对一个字段的符号引用#define CONSTANT_Methodref 10 //对一个类中方法的符号引用#define CONSTANT_InterfaceMethodref 11 //对一个接口中方法的符号引用#define CONSTANT_NameAndType 12 //对一个字段或方法的部分符号引用constant_pool:表类型数据集合,即常量池中每一项常量都是一个表,共有11种结构各不相同的表结构数据。这11种表都有一个共同的特点,即均由一个u1类型的标志位开始,可以通过这个标志位来判断这个常量属于哪种常量类型,常量类型及其数据结构如下表所示:
类型
简介
项目
类型
描述
CONSTANT_Utf8_info
utf-8缩略编码字符串
tag
u1
值为1
length
u2
utf-8缩略编码字符串占用字节数
bytes
u1
长度为length的utf-8缩略编码字符串
CONSTANT_Integer_info
整形字面量
tag
u1
值为3
bytes
u4
按照高位在前储存的int值
CONSTANT_Float_info
浮点型字面量
tag
u1
值为4
bytes
u4
按照高位在前储存的float值
CONSTANT_Long_info
长整型字面量
tag
u1
值为5
bytes
u8
按照高位在前储存的long值
CONSTANT_Double_info
双精度浮点型字面量
tag
u1
值为6
bytes
u8
按照高位在前储存的double值
CONSTANT_Class_info
类或接口的符号引用
tag
u1
值为7
index
u2
指向全限定名,常量项的索引
CONSTANT_String_info
字符串类型字面量
tag
u1
值为8
index
u2
指向字符串字面量的索引
CONSTANT_Fieldref_info
字段的符号引用
tag
u1
值为9
index
u2
指向声明字段的类或接口描述符CONSTANT_Class_info的索引项
index
u2
指向字段描述符CONSTANT_NameAndType_info的索引项
CONSTANT_Methodref_info
类中方法的符号引用
tag
u1
值为10
index
u2
指向声明方法的类描述符CONSTANT_Class_info的索引项
index
u2
指向名称及类型描述符CONSTANT_NameAndType_info的索引项
CONSTANT_InterfaceMethodref_info
接口中方法的符号引用
tag
u1
值为11
index
u2
指向声明方法的接口描述符CONSTANT_Class_info的索引项
index
u2
指向名称及类型描述符CONSTANT_NameAndType_info的索引项
CONSTANT_NameAndType_info
字段或方法的部分符号引用
tag
u1
值为12
index
u2
指向该字段或方法名称常量项的索引
index
u2
指向该字段或方法描述符常量项的索引
4、access_flags(访问标志) 占用2个字节。用来表明该class文件中定义的是类还是接口,访问修饰符是否定义为public;是否定义为abstract类型。类是否是final的。
标志名称
标志值
含义
ACC_PUBLIC
0x0001
是否为public类型
ACC_FINAL
0x0010
是否被声明为final,只有类可设置
ACC_SUPER
0x0020
是否允许使用invokespecial字节码指令,JDK1.2以后编译出来的类这个标志为真
ACC_INTERFACE
0x0200
标识这是一个接口
ACC_ABSTRACT
0x0400
是否为abstract类型,对于接口和抽象类,此标志为真,其它类为假
ACC_SYNTHETIC
0x1000
标识别这个类并非由用户代码产生
ACC_ANNOTATION
0x2000
标识这是一个注解
ACC_ENUM
0x4000
标识这是一个枚举
根据上面的表格,TestClass类的访问标志为0x0021 = ACC_PUBLIC | ACC_SUPER = 0x0001 | 0x0020
5、this_class 占用2个字节。 它是一个对常量池的索引。指向的是常量池中存储类名符号引用的CONSTANT_Class_info常量表(见下面常量池具体结构)。比如this_class=0x0001。则表示指向常量池中的第一个常量表。通常这个表是指向当前class文件所定义的类名。
6、super_class 占用2个字节 与this_class类似,指向存放当前class文件所定义类的超类名字的索引的CONSTANT_Class_info常量表。
7、inteface_count、interfaces
interface_count是class文件所定义的类直接实现的接口或父类实现的接口的数量。占2个字节。intefaces包含了对每个接口的CONSTANT_Class_info常量表的索引。
由于interface_count为0,所以接口索引集合interfaces大小为0,即在编译后的二进制文件中不存在interfaces这项内容。
8、fields_count、fields
fields_count字段计数器,表明了类中字段的数量 。fields是不同长度的field_info表的序列。这些field_info表中并不包含超类或父接口继承而来的字段。field_info表展示了一个字段的信息,包括字段的名字,描述符和修饰符。如果该字段是final的,那么还会展示其常量值。注意,这些信息有些存放在field_info里面,有些则存放在field_info所指向的常量池中。fields:字段表集合,一组字段表类型数据的集合,字段表包括access_flags,name_index,descriptor_index,attributes_count和attributes[attributes_count]。
9、method_count、methods
与字段类似,method_count表明类中方法的数量和每个方法的常量表的索引。methods表明了不同长度的method_info表的序列。methods:方法表集合,一组方法表类型数据的集合。方法表结构和字段表结构一样包括access_flags,name_index,descriptor_index,attributes_count和attributes[attributes_count]。
标志名称
标志值
含义
ACC_PUBLIC
0x0001
字段是否为public
ACC_PRIVATE
0x0002
字段是否为private
ACC_PROTECTED
0x0004
字段是否为protected
ACC_STATIC
0x0008
字段是否为static
ACC_FINAL
0x0010
字段是否为final
ACC_SYNCHRONIZED
0x0020
字段是否为synchronized
ACC_BRIDGE
0x0040
方法是否是由编译器产生的桥接方法
ACC_VARARGS
0x0080
方法是否接受不定参数
ACC_NATIVE
0x0100
字段是否为native
ACC_ABSTRACT
0x0400
字段是否为abstract
ACC_STRICTFP
0x0800
字段是否为strictfp
ACC_SYNTHETIC
0x1000
字段是否为编译器自动产生
10、attributes_count 和 attributes属性表
在Class文件、属性表、方法表中都可以包含自己的属性表集合,用于描述某些场景的专有信息与Class文件中其它数据项对长度、顺序、格式的严格要求不同,属性表集合不要求其中包含的属性表具有严格的顺序,并且只要属性的名称不与已有的属性名称重复,任何人实现的编译器可以向属性表中写入自己定义的属性信息。
- Class类文件的结构
- Class类文件的结构
- Class类文件的结构
- Class类文件的结构
- Class类文件的结构
- Class类文件的结构
- Class类文件的结构
- Class类文件结构
- Class类文件结构
- class类文件结构
- Class类文件结构
- Class类文件结构
- Class类文件结构
- CLASS类文件结构
- Class类文件结构
- Class类文件结构
- Class类文件结构
- java虚拟机Class类文件的结构
- ResourceBundle读取配置文件
- 不允许root运程登陆Linux
- Java+mybatis+spring中读取BLOB类型异常
- git总结(二)----常用命令
- 商业模式系列-序
- Class类文件的结构
- hdu 5514 Frogs 2015沈阳区域赛 数论 欧拉 好题 开心的题
- Wordpress可以用来做什么?
- mac工具--通过 arp 欺骗抓取局域网内设备数据包
- Linux 下安装配置 JDK1.7
- 面向对象对象之间的关系
- git总结(三)修改提交的author和email
- mysql 学习记录(十九)--Innodb表锁
- 【UML】 之 用例图