构造代码块用于替代重复的初始化逻辑,它在每次实例化时自动执行,优先于构造器体但晚于字段初始化,且每new一次执行一次。

构造代码块用来干啥:替代重复的初始化逻辑
当一个类有多个构造器,且它们开头都做相同的事(比如校验参数、初始化默认值、记录日志),把这些逻辑塞进每个 constructor 里,不仅冗余,还容易漏改或改不一致。构造代码块就是为这事生的——它在每次实例化时自动执行,且优先于构造器体内的代码,但晚于字段初始化。
它不是静态的,不依赖类加载;也不是方法,不能被显式调用;更不是生命周期钩子,没有上下文参数。就一条:只要 new 了,它必跑,且每 new 一次就跑一次。
怎么写才生效:位置和语法硬约束
构造代码块长得像没名字的方法体,用 {} 包裹,直接写在类里、所有方法外。它不能加访问修饰符,不能带参数,不能有返回值,也不能用 static(那是静态代码块)。
常见错误现象:IllegalAccessError 或编译失败,往往是因为把它误写成方法(加了 void)、当成静态块(加了 static)、或者塞进了某个方法体内。
立即学习“Java免费学习笔记(深入)”;
- ✅ 正确位置:在类定义内、
constructor和普通方法之间(顺序不影响执行时机) - ❌ 错误写法:
public { ... }、static { ... }、void init() { ... } - ⚠️ 注意:多个构造代码块按源码出现顺序依次执行,不是按构造器调用顺序
和构造器、字段初始化谁先谁后
实例化时的真实执行顺序是固定的:字段默认值 → 字段显式初始化(如 int x = 1;)→ 构造代码块 → 构造器体。这个顺序决定了你能安全依赖什么。
比如字段已赋初值,构造代码块里可以读 this.x;但还不能调用依赖完整对象状态的 this.someMethod()(除非该方法不依赖未初始化字段)。
- 字段初始化表达式在构造代码块前完成,所以块内可安全读取
- 构造代码块在
super()或this()调用之后才执行(即父类构造器已完成) - 如果构造器第一行是
this(...),那当前类的构造代码块会在目标构造器的代码块之后、其构造器体之前执行
别把它当万能胶:适用边界和坑点
构造代码块适合轻量、无参、与具体构造器参数无关的通用初始化。一旦逻辑需要参数、要抛受检异常、或要根据构造器入参分支处理,它就撑不住了——这时候老老实实提成私有方法,在每个构造器里调用更清晰。
性能上几乎无开销,JVM 会把它“内联”进每个构造器字节码里,但语义上它仍是独立结构,调试时堆栈里能看到对应行号。
- ❌ 别在块里 throw
IOException:构造器没声明,编译直接报错 - ❌ 别指望它做资源分配后自动清理:没有对应的“析构块”,得靠
try-with-resources或显式 close - ✅ 适合场景:统一打日志、设置默认枚举状态、初始化线程不安全的集合、校验 this 引用是否为 null(极少,但合法)
真正容易被忽略的是:它不参与继承链的重写或覆盖,子类 new 时只会执行自己类里的构造代码块,父类的也执行,但两者完全隔离——别指望子类块能“接管”或“跳过”父类块。






