java变量初始化核心在于区分静态初始化(类加载时仅执行一次,先父后子、按文本顺序)与实例初始化(每次new都执行,父类实例块→父类构造器→子类实例块→子类构造器)。

Java变量初始化顺序的核心,在于分清「类加载时的静态初始化」和「对象创建时的实例初始化」——它们是两个独立阶段,触发时机、执行次数、作用范围都不同。
类加载阶段:只做一次,管所有静态成员
类在首次被主动使用(比如 new 实例、调用静态方法、访问非编译期常量的静态字段)时,才完成完整加载并进入初始化阶段。此时 JVM 执行 <clinit></clinit> 方法,按源码文本顺序处理:
- 父类的静态变量显式赋值和静态代码块(先父后子)
- 子类的静态变量显式赋值和静态代码块
- 静态变量在“准备”阶段已设默认值(如 0、null),“初始化”阶段才执行赋值语句和 static{} 块
- 声明在后的静态变量,若在前面的 static{} 中被引用,值为对应类型的默认值(不是未定义,而是 0 或 null)
对象实例化阶段:每次 new 都走一遍,管当前对象的非静态部分
每次执行 new X(),JVM 在堆中分配内存后,立即开始实例初始化,执行 <init></init> 方法,顺序固定:
- 父类的实例变量赋值 + 实例代码块(按源码顺序交错执行)
- 父类构造器(隐式或显式 super() 调用)
- 子类的实例变量赋值 + 实例代码块(同样按声明顺序)
- 子类构造器体内的代码
注意:所有实例字段在分配内存时已设默认值(int=0、Object=null),之后才执行显式初始化和代码块。
关键区别一目了然
触发时机:类初始化由“首次主动使用”触发;实例初始化由“每次 new”触发。
执行次数:静态部分一生只跑一次;实例部分每建一个对象就跑一次。
依赖关系:子类初始化前,父类静态部分必须已完成;子类实例化前,父类实例部分必须已执行完。
不能混用:在静态上下文中(static{} 或静态变量初始化)调用非静态方法或访问实例字段,编译直接报错。
常见误区提醒
声明引用(如 Parent p;)或创建数组(如 Parent[] arr = new Parent[5];)不会触发类的静态初始化,仅完成类加载的“准备”阶段。
构造器里调用可被重写的方法,实际执行的是子类重写后的方法——但此时子类实例变量可能还没初始化(仍在父类构造器中),容易引发空指针或逻辑错误。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











