静态代码块在类加载时执行一次,构造代码块每次new对象时在构造方法体前执行;前者属类初始化、后者属实例初始化,执行顺序为父类静态→子类静态→父类实例→子类实例。

静态代码块在类加载时执行一次,构造代码块在每次 new 对象时、构造方法体之前执行。二者不共存于同一阶段:前者属于类初始化,后者属于实例初始化;顺序上一定是静态优先、父类先行、按源码位置依次展开。
静态代码块:只跑一次,类加载即触发
静态代码块用 static {} 定义,JVM 在类首次被主动使用(如 new 实例、调用静态方法、访问静态字段)时,将其与静态变量赋值一起编译进 <clinit></clinit> 方法,从上到下顺序执行。
- 多个静态块按源码书写顺序依次运行,不能跳过或倒置
- 可用来做一次性资源准备,比如数据库连接池启动、配置加载、日志器初始化
- 只能访问静态成员,不能用 this、实例变量或非静态方法
- 哪怕没创建任何对象,只要类被加载,它就执行——例如访问
MyClass.FLAG就足以触发
构造代码块:每次 new 都走一遍,紧贴构造逻辑前
构造代码块就是类中直接写的 {}(无 static),编译器会把它自动插入每个构造方法的开头,在 super() 或 this() 调用之后、构造方法体之前执行。
- 适合抽取多个构造器共用的初始化动作,比如统一设置默认状态、校验必填字段
- 可以访问实例变量、静态成员,也能使用 this,但要避免调用可能被子类重写的方法(此时子类字段尚未赋值)
- 多个构造块也严格按源码顺序执行,和字段显式初始化(如
String name = "Tom";)地位等同 - 子类的构造块不会继承父类的构造块,仅在本类 new 时生效
父子类混合场景下的完整执行链条
创建一个子类对象,实际经历两个阶段叠加:类加载阶段执行静态部分,对象创建阶段执行实例部分。最终顺序固定为:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 父类静态变量赋值 + 静态代码块(从上到下)
- 子类静态变量赋值 + 静态代码块(从上到下)
- 父类实例变量赋值 + 构造代码块(从上到下)→ 父类构造方法体
- 子类实例变量赋值 + 构造代码块(从上到下)→ 子类构造方法体
注意:父类构造方法执行时,子类所有实例字段仍为默认值(0 / null / false)。若父类构造器中调用了被子类重写的方法,而该方法又读取子类字段,就会得到未初始化的结果。
验证与避坑:用日志看清真实流程
别靠记忆猜顺序,加带标识的日志最可靠。例如在以下位置输出:
- [S] 静态块内:打印 “S: 父类静态块”
- [I] 构造块内:打印 “I: 子类构造块”
- [C] 构造方法第一行:打印 “C: 子类构造器”
运行 new Child() 后观察输出,就能直观确认是否符合预期。常见陷阱包括:静态块引用后声明的静态变量(编译报错)、构造块里调用子类重写方法导致 NPE、误以为构造块会继承到子类。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










