非静态代码块每次创建对象时都会执行,是JVM在构造函数前自动插入的初始化逻辑,按源码顺序执行,可访问实例成员,与构造函数绑定而非具体写法。

非静态代码块每次创建对象时都会执行,这是 JVM 在对象实例化过程中自动插入的初始化逻辑。掌握它,关键不是背顺序,而是看清“谁在什么时候、为什么被触发”。
非静态代码块的本质:构造函数前的自动插入段
JVM 在每次调用构造函数前,会把类中所有非静态代码块(按源码顺序)的内容,原样“插”到构造函数体开头。它不依赖 new 的写法,也不受访问修饰符影响,只要 new 出一个实例,就必走这一环。
- 哪怕构造函数是空的,非静态代码块仍会执行
- 多个非静态代码块按书写顺序依次执行,中间可穿插字段赋值
- 它可以访问静态和非静态成员(包括 this、普通字段、方法),因为此时对象内存已分配,只是尚未完成初始化
用两次 new 直观验证“多次调用”特性
写一个含日志输出的非静态代码块,然后连续 new 两次:
class Demo {{ System.out.println("非静态代码块运行"); }
Demo() { System.out.println("构造函数运行"); }
public static void main(String[] args) {
new Demo();
new Demo();
}
}
输出一定是:
- 非静态代码块运行
- 构造函数运行
- 非静态代码块运行
- 构造函数运行
这说明:它不绑定某个特定构造函数,而是绑定“每一次对象创建动作”。
结合字段初始化理解执行时机
非静态代码块常用于统一初始化实例字段,尤其当多个构造函数有重复逻辑时。例如:
class Person {private String name;
private int age;
{
name = "unknown";
age = 0;
System.out.println("通用初始化完成");
}
Person() {}
Person(String name) { this.name = name; }
}
无论调用哪个构造函数,name 和 age 都会先被设为默认值——因为非静态代码块总在构造函数体执行前跑完。
注意陷阱:不能在静态上下文中引用它
非静态代码块属于对象级别,所以:
- 不能出现在 static 方法里(语法报错)
- 不能在静态代码块中通过 this 或实例变量间接触发(this 还不存在)
- 若在类中定义了 static final 常量并直接使用,可能跳过静态代码块,但绝不会跳过非静态代码块——只要 new,它就来
不复杂但容易忽略










