不考虑作用域修饰符,成员变量的类型有:
static final 类型、仅static类型、仅final类型、普通类型
并且,我们在定义成员变量的时候,还可以通过=赋初值。(其中包含final时强制要求赋初值)
那么,这些赋值操作都是在哪个阶段完成的呢?
按照执行的先后顺序
1. 对于staticfinal类型成员变量,会在class文件的Fields中增加ConstantValue属性,在准备阶段,就由虚拟机设置好常量值
2. 对于仅static类型成员变量,会在准备阶段,设置默认初始值,在初始化阶段,将赋值语句和static{}代码块合并成<clinit>方法,在<clinit>方法中赋值
3. 对于仅final类型成员变量、普通成员变量,会将赋值语句和原构造函数合并,在新构造函数中赋值 (虽然仅final类型成员变量也有ConstantValue属性,但是其作为实例成员变量,只有在堆上分配了对象以后才能赋值,所以只能是到了这里才赋值。所以此时的ConstantValue属性其实并没有什么用)
仅final类型成员变量,编译器会要求要么在定义时赋初值,要么在构造函数中赋初值。
普通成员变量,如果没有设置初始值,也会为其设置默认初始值。(应该也是在上述的第3阶段中,在堆中分配了对象的内存空间以后)
默认初始值的规则如下
类型 | 默认初始值 |
int/byte/short/char/boolean | 0 |
long | 0 |
float | 0 |
double | 0 |
引用 | null |
以如下代码为例(使用double类型验证,因为int类型会直接将数值生成到字节码指令中去)
Java Code
1 | package com.test.a; |
常量池中的内容为
m6具有ConstantValue属性,指向常量池中的600d,会在准备阶段就设置初始值。
<clinit>将仅static类型成员变量的赋值语句和static{}静态代码块合并,这里设置了m4
<init>将构造函数中的语句和其他类型成员变量的赋值语句合并,这里设置了m2、m5
执行结果如下,可以看到m1、m3默认值