根据前文 jvm之字节码解读——认识字节码 ,我们可知,java的字节码文件结构为
前文已经对常量池进行了分析
我们先把常量池的内容贴一下
Constant pool:
#1 = Methodref #4.#20 // java/lang/Object."<init>":()V
#2 = Fieldref #3.#21 // com/bill/MyByteCodeTest1.a:I
#3 = Class #22 // com/bill/MyByteCodeTest1
#4 = Class #23 // java/lang/Object
#5 = Utf8 a
#6 = Utf8 I
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 Lcom/bill/MyByteCodeTest1;
#14 = Utf8 getA
#15 = Utf8 ()I
#16 = Utf8 setA
#17 = Utf8 (I)V
#18 = Utf8 SourceFile
#19 = Utf8 MyByteCodeTest1.java
#20 = NameAndType #7:#8 // "<init>":()V
#21 = NameAndType #5:#6 // a:I
#22 = Utf8 com/bill/MyByteCodeTest1
#23 = Utf8 java/lang/Object
下面,对紧跟在版本号的字段——Access Flags(访问修饰符)进行分析
Access Flags(访问修饰符)
访问修饰符这个字段比较简单,它的意思这个类的访问修饰符(例如public/static/final)。它占据2个字节
先看看我们这里的访问修饰符是什么
访问修饰符是0x0021(化成2进制就是:0000 0000 0010 0001)
再看以下表
我们对比一下0000 0000 0010 0001,第0位和第5位分别是1,对应的是public和super
public的意思就不多说了,这里ACC_SUPER标志的存在是为了向后兼容Sun较早的编译器为Java编程语言编译的代码,跟jvm如何执行方法是有关的(例如多态的方法执行)
ps:其实这张表我是在网上找的,不知道为什么有2个5/6/7,看上去这样冲突了,如果有人知道答案,可以在评论区说一声
This Class(本类)
这个字段也比较简单,其实就是这个类是哪个,占据2个字节,内容的意义是指向常量池的常量,数值就是常量在常量池的下标,这里为0x0003
我们看一下常量池里第3个常量是什么
#3 = Class #22 // com/bill/MyByteCodeTest1
一目了然,其实就是我们自己这个类
Super Class(父类)
这个字段和This Class很像,只是这里描述的是父类的信息,也是占据2个字节,这里为0x0004
我们看一下常量池里第4个常量是什么
#4 = Class #23 // java/lang/Object
意思就是,这个类的父类是Object类
Interfaces(接口)
顾名思义,这个字段的意思就是实现了哪个接口,由2+N个字节组成,前2个字节表示接口的个数,后面跟着的内容就是实现的接口(常量池的index)
ps:所以有面试官问你java的类是不是可以实现无限多个接口,你知道该怎么回答了吧?(最多可以实现2的16次方-1个接口)
因为这里没有实现的接口,所以这里的值为0x0000
这个字段比较简单,这里不做详细说明了
Fields(成员变量)
这里Fields的意思就是我们通常理解的field,即成员变量,在我们的例子里,就只有a这个成员变量
这个字段占据的空间是2+n字节,前面2个字节表示成员变量的个数
由于我们这里只有1个成员变量,所以这里的值为0x0001
我们思考一下,一个成员变量的定义是不是这样构成的
访问修饰符(例如public/static/final等)+ 类型(如int/double等)+ 成员变量的名字(这里为a)
所以,要理清楚这个字段是怎么表述的,还要借助另一个表
我们一个个对,access_flags其实就是对应的我们的访问修饰符(例如public/static/final等,跟上文提到的Access_Flag类似),name_index表示的就是成员变量的名字,descriptor_index表示的就是类型(如int/double等),attributes相关的东西我们暂时不看
我们来对一下字节码文件
我们可以看到,这里
access_flags是0x0002(二进制的0000 0000 0000 0010,对比上表,即为private)
name_index是0x0005,找到常量池序号为5的常量
#5 = Utf8 a
其实这里表示的意思就是这个字段的名字为“a”
descriptor_index是0x0006,找到常量池序号为6的常量
#6 = Utf8 I
前面有一篇文章介绍了,这个I的代表的意思是int(jvm之字节码解读——认识字节码文件结构解析(常量池))
attributes是0x0000,就是说这个成员变量没属性
所以,综合上面所述,这里要表达的意思就是
private int a