静态代码块在类加载的初始化阶段执行一次,按源码顺序修改方法区静态变量,默认值被覆盖;不可访问非静态成员;未被引用的静态变量及对应代码块不执行。

静态代码块只影响方法区的静态变量
静态代码块在类加载的“初始化阶段”执行,此时它能修改方法区中已分配内存的静态变量。这些变量在“准备阶段”已被赋予默认值(比如 int 是 0,Object 是 null),而静态代码块的作用就是覆盖这个默认值,完成程序员指定的显式初始化。
关键点包括:
- 多个静态代码块按源码中出现顺序依次执行,且仅执行一次
- 它不能访问非静态成员——因为对象还没创建,实例变量根本不存在于堆中
- 只有被实际访问的静态字段,其初始化逻辑才会进入
<clinit>方法;未被引用的静态变量和对应代码块不会执行
实例代码块操作的是堆中的对象状态
不带 static 的代码块属于实例初始化逻辑,每次调用 new 创建对象时都会执行。它作用的对象是堆内存里的具体实例,负责给实例变量赋值或执行通用初始化动作。
这类代码块在编译后会被插入到每个构造器开头(位于 super() 调用之后),所以它总在构造方法体之前运行。它和字段显式初始化语句地位等同,都按类中声明顺序执行。
立即学习“Java免费学习笔记(深入)”;
例如:
- 先执行
private int x = 10; - 再执行
{ y = 20; } - 最后才进入构造方法体
字段声明顺序决定初始化先后
Java 实例字段严格按源码文本顺序初始化。如果某个字段的初始化表达式依赖于后面声明的字段,那么它取到的是后者当前的默认值,而非显式赋的值。
典型陷阱示例:
private int a = getValue();private int b = 15;private int getValue() { return b; }
结果 a = 0,因为 b 还没走到显式赋值那步,仍为 int 默认值 0。
父子类之间初始化有明确层级约束
类加载时,父类静态部分一定先于子类静态部分执行;创建对象时,父类实例变量与代码块也一定先于子类执行。
完整顺序可归纳为:
- 父类静态变量 → 父类静态代码块
- 子类静态变量 → 子类静态代码块
- 父类实例变量 → 父类实例代码块 → 父类构造器
- 子类实例变量 → 子类实例代码块 → 子类构造器
这种分层+顺序的机制确保了继承关系下变量状态的可控性和可预测性。


















