Class文件结构和字节码

Class文件结构

class文件是一种8位字节的二进制流文件, 各个数据项按顺序紧密的从前向后排列, 相邻的项之间没有间隙, 这样可以使得class文件非常紧凑, 体积轻巧, 可以被JVM快速的加载至内存, 并且占据较少的内存空间。 我们的Java源文件, 在被编译之后, 每个类(或者接口)都单独占据一个class文件, 并且类中的所有信息都会在class文件中有相应的描述, 由于class文件很灵活, 它甚至比Java源文件有着更强的描述能力。

魔数,claa文件版本

魔术是CAFEBABE,class文件版本表示字节码版本,防止低版本JVM运行高版本代码。

常量池

由于常量池的数量是不固定的,所以在常量池入口需要放置一项u2(即2个字节)类型的数据,代表常量池容量计数值(constant-pool-count)(从1开始,将0表示不引用任何常量).常量池中主要存放两大类常量:字面量(Literal)和符号引用(Synbolic Reference)。常量池是class文件中占用空间最多的。

一个常量池项cp_info的数据结构如下

cp_info{
    u1 tag;
    ...
}

例如

CONSTANT_Long_info{
    u1 tag=5;
    u4 high_bytes;
    u4 low_bytes;
}

CONSTANT_utf8_info{
    u1 tag=1;
    u2 length;
    u1 byte[length];
}

其中的tag就是下表中的标志。

类型 标志 描述
CONSTANT_utf8_info 1 UTF-8编码的字符串(字面)
CONSTANT_Integer_info 3 int整形字面量(字面)
CONSTANT_Float_info 4 float浮点型字面量(字面)
CONSTANT_Long_info long长整型字面量(字面)
CONSTANT_Double_info double双精度浮点型字面量(字面)
CONSTANT_Class_info 类或接口的全限定名(引用)
CONSTANT_String_info String类型的常量对象(引用)
CONSTANT_Fieldref_info 类中的字段(引用)
CONSTANT_Methodref_info 10 类中的方法(引用)
CONSTANT_InterfaceMethodref_info 11 类所实现的接口方法(引用)
CONSTANT_NameAndType_info 12 字段和方法的名称和类型(引用)
CONSTANT_MethodHandle_info 15 表示方法句柄(引用)
CONSTANT_MothodType_info 16 标志方法类型(引用)
CONSTANT_InvokeDynamic_info 18 表示一个动态方法调用点(引用)

上面所有标记为引用的,最终都要具体内容都要引用到一个标志为字面的cp_info来存储具体信息。

CONSTANT_String_info{
    u1 tag = 8;
    u2 String_index;//指向某个CONSTANT_utf8_info结构体
}

具体请参考https://blog.csdn.net/wangtaomtk/article/details/52267548

访问标志

只有两个字节。标志该类是否为abstract,final,public,是否为接口等等。

类索引

一个U2类型,指向CONSTANT_Class_info类型的常量,记录本类的全限定名。

父类索引

一个U2类型,指向CONSTANT_Class_info类型的常量,记录父类的全限定名。

接口索引集合

接下来不定长的字节表示该类实现的接口。和上面类似。

字段表集合

一个字段用一个字段表表示,字段的集合当然要用字段表集合表示了。

类型 名称 数量
u2 access_flags 1
u2 name_index 1
u2 descriptor_index 1
u2 attributes_count 1
attribute_info attributes attributes_count

access_flags的作用和类的访问标志作用类似。
name_index是本字段的索引,指向常量池中的一个CONSTANT_NameAndType_info类型。
descriptor_index用于描述该字段的数据类型
attributes_count属性表长度(非必须)
attributes 属性表(非必须)

方法表集合

方法表的组成和字段表一摸一样。只不过,descriptor_index还需要包含字段的数据类型、参数列表、返回值。另外,属性表中有一个code项目,用来存储源代码。
如果本class没有重写父类的方法,java还没有傻到把父类的方法原封不懂的拷贝到子类的方法表中。

字节码

每个字节码命令都有自己的助记符。(和汇编语言相同)。助记符的第一个字母表示自己所操作的数据类型。字节码设计遵循公有设计和私有实现原则。所有JVM都遵循一致的字节码规范,但是内部实现各不相同

加载和存储指令

运算指令

类型转换指令

对象创建和访问指令

JVM中的数组是一个比较特殊的问题。所以创建数组,把元素存储到数组,取数组长度,都有自己的指令

控制转移指令

方法调用和返回指令

异常处理指令

同步指令

monitorenter和monitorexit。(将栈顶元素作为锁进行同步)

猜你喜欢

转载自blog.csdn.net/define_us/article/details/80533919
今日推荐