Java实例变量默认值赋值时机是什么时候?

实例变量在什么时候会被赋默认值例如int赋0, boolea赋false。

public class test{
    public int a = 10;
    ......
}

我希望从JVM的角度出发,有相应的证明或者资料证明吗?

阅读 1.6k
3 个回答

是在对象创建过程中初始化并完成赋值的(目录:自动内存管理 -> HotSpot虚拟机对象探秘 -> 对象的创建)
详细可参看周志明老师的JVM这本书,这里给你截个图
image.png

  1. 类加载阶段的准备阶段

    • 当Java类被加载到JVM中时,会经历一系列阶段,其中在“准备”阶段会给类的实例变量分配内存空间,并赋予默认值。对于基本数据类型,如int会被初始化为0,boolean会被初始化为falsefloat会被初始化为0.0f等;对于引用类型,则会被初始化为null
    • 这一阶段是由JVM自动完成的,它的主要目的是为类的静态变量和实例变量分配内存并设置初始值,为后续的初始化阶段做准备。这些默认值是在类加载的字节码层面就确定的行为。从字节码的角度来看,在准备阶段,JVM会按照Java虚拟机规范中定义的规则为变量分配内存和设置初始值。
    • 以你提供的test类为例,在类加载的准备阶段,a这个实例变量已经在内存中有了空间,并且被初始化为0。
  2. 对象实例化阶段(初始化之后)

    • 在对象实例化阶段,也就是调用构造函数(如果没有显式定义构造函数,JVM会提供一个默认构造函数)之前,实例变量已经有了默认值。然后,在执行构造函数的代码时,如果有对实例变量的显式赋值操作(如public int a = 10;),这个时候会将显式赋值覆盖掉之前的默认值。
    • 从字节码指令的角度来看,在对象初始化方法(<init>)中,会有指令将10赋值给a。这个过程是在对象真正被创建并初始化的时候发生的。
    • 证明可以通过字节码分析工具来查看。例如,使用javap -c命令来反编译test类的字节码文件,可以看到在<init>方法中有类似aload_0(将this引用压入操作数栈)、bipush 10(将常量10压入操作数栈)和putfield(将操作数栈顶的值存入实例变量a)这样的字节码指令,这些指令表明了在对象初始化过程中对a的赋值操作。

在JVM规范中,详细规定了类加载和对象初始化的过程,这些规则保证了实例变量默认值的正确赋值时机。具体可以参考《Java虚拟机规范(Java SE 8版)》,其中对于类加载过程中的准备阶段和对象初始化阶段都有精确的定义和描述,这是理解变量赋值时机的权威资料。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏