[jvm解析系列][七]字段表集合、volatile、volatile和属性表集合,你的变量该如何存储?

来源:互联网 发布:阿里云 发票退票 编辑:程序博客网 时间:2024/04/29 09:17

上段我们说到一个类的基本构成,今天我们来讲一下类的内部结构。类的内部一般情况下由类的成员变量(类字段),方法和内部类等构成。

1、字段表

不好意思我们这一次需要先上字段表的内容然后一个一个讲解,不能像前面那样像设计者一样一个一个的推出来了,主要原因还是字段表里包含了属性表。


access_flags

还记得我们在上一篇里讲的,在类的继承关系之后应该就是field_info他主要描述接口或者类中声明的变量。field包括类和实例级变量(声明在方法外的变量)。那么我们想一下一个成员变量应该有什么?我们平时这样声明一个变量。如:private int a = 0;所以,首先要有的应该是一个作用域(public private protected),接下来是一个int,这个被叫做字段数据类型(也就是int或者其他类型,还有对象,数组)。当然有时候我们还会申请这样一个变量:public static final int a =0;那么我们应该还有一个用来表示他是否是final的变量,被叫做可变性。还有一个static变量需要描述。当然不能缺少了一个enum类型的变量,有时候我们还会见到一些不常见的修饰符,如volatile、transient。

volatile关乎到jvm的变量赋值问题,在jvm中,a++这个方法不是每次都要去堆内直接操作内存的,他被编译成了四个部分

1、把内存里的变量复制到自己的方法栈内

2、进行完修改,这里有赋值和加两部份

3、再赋值回去。这样如果有A,B两个线程同时访问变量a,并且同时修改+1,在返回堆中的时候a并不会+2而是+1。

所以volatile变量声明的变量可以保证每次读取的数据都是最新数据,但是注意,不可以保证原子性。

除此之外volatile还可以保证指令重排优化,这里我们以后会讲。

2、transient,在序列化的时候,被transient修饰的变量不参与序列化,默认不被transient修饰。

综上所述,一个字段表应该包括字段的作用域,static,final,volatile,transient,是否由编译器自动生成的,字段是否enum。如下图所示


name_index,descriptor_index

前面我们已经说过了,这个位置应该是一个field_info的表,既然是一个表就不可能仅仅只有上面一个最多u2类型的字段构成。所以除此之外我们还需要字段的简单名称和描述符。

1、简单名称就是如int a;a就是简单名称

2、描述符:描述符主要用来描述字段的数据类型、方法的参数列表和返回值。这一块不在JVM范围内,后面会在杂项中补充。

attributes

最后也就是一个需要细细讲解的部分,属性,在Class文件,字段表,放发表中都可以携带自己的属性表集合。

一个属性应该是下列这样的结构:


attribute_name_index 代表了一个常量池关于属性名称的索引。

而info代表了每一个属性的内容,我们并不强求info的长度,我们只需要一个u4类型的length来表示这个属性到底有多长就可以了。

而一个字段表内可以声明如下的属性:


关于每一个属性表的具体结构,我们会到放到下一章,因为方法表中也有属性,综合在一起讲一些比较常见的属性。


1 0