Java虚拟机系列二:class字节码详细分析

索引:

Java虚拟机系列一: Java文件如何被加载执行

全文的分析都基于class字节码,它与android dex字节码有很大的区别。class字节码是以类为单位组织的,而dex是多个类的集合

一.class字节码是什么?

字节码是由jvm规范所定义的一套描述class内容的结构,由于它的描述与指令集的平台无关性,只要能够将自己的语言翻译成为字节码,就都能被虚拟机执行,这样的语言如java,groovy,kotlin等。hotpot虚拟机是jvm规范的标准实现。

二.class字节码的简单例子看全貌

眼见为实,我们定义一个Test.java类

public class Test {
    static String a = "hucaihua";
}
复制代码

通过编译得到Test.class,通过010Editor查看它的内容,可以看出它是用字节为单位组织的二进制内容,也就是说它的本质是用01串存储的二进制流。

在这里软件为了方便展示,以16进制来表示,一个16进制需要用4位二进制来表示,因此这里的每一个隔开的数据,代表的就是一个字节8位。

CA FE BA BE 00 00 00 37 00 14 0A 00 05 00 0F 08
00 10 09 00 04 00 11 07 00 12 07 00 13 01 00 01
61 01 00 12 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53
74 72 69 6E 67 3B 01 00 06 3C 69 6E 69 74 3E 01
00 03 28 29 56 01 00 04 43 6F 64 65 01 00 0F 4C
69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65 01 00
08 3C 63 6C 69 6E 69 74 3E 01 00 0A 53 6F 75 72
63 65 46 69 6C 65 01 00 09 54 65 73 74 2E 6A 61
76 61 0C 00 08 00 09 01 00 08 68 75 63 61 69 68
75 61 0C 00 06 00 07 01 00 04 54 65 73 74 01 00
10 6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63
74 00 21 00 04 00 05 00 00 00 01 00 08 00 06 00
07 00 00 00 02 00 01 00 08 00 09 00 01 00 0A 00
00 00 1D 00 01 00 01 00 00 00 05 2A B7 00 01 B1
00 00 00 01 00 0B 00 00 00 06 00 01 00 00 00 01
00 08 00 0C 00 09 00 01 00 0A 00 00 00 1E 00 01
00 00 00 00 00 06 12 02 B3 00 03 B1 00 00 00 01
00 0B 00 00 00 06 00 01 00 00 00 02 00 01 00 0D
00 00 00 02 00 0E
复制代码

三.class字节码的结构体

class结构的官方说明

我们知道,class是格式化的二进制流,也就是它的二进制流是按照jvm虚拟机规范规定的格式来表示内容的,在jvm中class定义如下:

ClassFile {
    u4             magic;               //魔数,固定值0xCAFEBABE
    u2             minor_version;       //次版本号
    u2             major_version;       //主版本号
    u2             constant_pool_count; //常量池的个数
    cp_info        constant_pool[constant_pool_count-1];  //常量池内容
    u2             access_flags;        //class 访问标识
    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];          //属性内容
}
复制代码

其中 u4,u2都是固定长度的描述字段,u4长度为4个字节,u2长度为2个字节。

cp_info , field_info , method_info , attribute_info 为结构体,每个结构体有单独的定义,并且它们的长度都是变化的。

四.class结构体重点结构说明

4.1 cp_info(18种常量类型的描述)

cp_info是class中占用字节数最多的块,它用不同的结构体定义了18种常量类型,这18种常量类型都用tag来表示它的具体类型。
class_cp_info

下图分析了CONSTANT_Class_info中的实际内容,其它内容的查找方式一样,不再继续分析。

class_def_analysis

4.2 field_info(字段描述)

field_info的定义如下:

field_info {
    u2             access_flags; //访问标志 
    u2             name_index; //名字在常量中的索引
    u2             descriptor_index; //描述在常量中的索引
    u2             attributes_count; //属性的个数
    attribute_info attributes[attributes_count]; //属性列表
}
复制代码
  • access_flags 访问标志一共包含如下9类,常用的如public,static,private,protected等:
Flag Name	Value	Interpretation
ACC_PUBLIC	0x0001	Declared public; may be accessed from outside its package.
ACC_PRIVATE	0x0002	Declared private; usable only within the defining class.
ACC_PROTECTED	0x0004	Declared protected; may be accessed within subclasses.
ACC_STATIC	0x0008	Declared static.
ACC_FINAL	0x0010	Declared final; never directly assigned to after object construction (JLS §17.5).
ACC_VOLATILE	0x0040	Declared volatile; cannot be cached.
ACC_TRANSIENT	0x0080	Declared transient; not written or read by a persistent object manager.
ACC_SYNTHETIC	0x1000	Declared synthetic; not present in the source code.
ACC_ENUM	0x4000	Declared as an element of an enum.
复制代码

4.3 attribute_info (属性描述)

属性描述信息可以作用于ClassFile , field_info,method_info,cod_attribute的描述。

我们常见的例如泛型,注解等都属于attribute_info的范畴。

它的定义如下:

attribute_info {
    u2 attribute_name_index; //属性名字如<Signature>表示泛型,<RuntimeVisibleAnnotations>表示注解等
    u4 attribute_length; //属性长度
    u1 info[attribute_length]; //属性信息
}
复制代码

下图用一个例子来说明属性
class_attribute

4.4 method_info (方法描述)

方法描述的定义与field_info一致,不再重复说明:

method_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}
复制代码

方法描述(method_info)与字段描述(field_info)最大的区别在于attribute_info不一样,

所有method_info都包含一个attribute_info,它的名字叫code,用于包含方法的指令信息。

下图体现了我们定义的get方法中的指令信息
class_method_instruction

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享