java代码块执行顺序为:先静态后实例、先父类后子类;静态部分在类首次主动使用时执行一次,按父类到子类、变量默认值→显式赋值/静态块顺序进行;实例部分每次new时执行,父类构造完成才执行子类,遵循默认值→赋值/构造块→构造函数体流程。

掌握Java代码块执行顺序,关键在于把抽象流程变成可观察、可验证的动作。不是背口诀,而是让每一步初始化都在控制台“开口说话”。
静态部分:类加载时一次性触发,父类必须先到位
只要首次主动使用类(比如 new 子类、调用子类静态方法、访问非编译期常量的静态字段),JVM 就会启动类加载流程,并强制先完成父类的静态初始化。
- 父类静态变量默认值 → 父类静态变量显式赋值 + 静态块(按源码从上到下)
- 子类静态变量默认值 → 子类静态变量显式赋值 + 静态块(按源码从上到下)
- 整个过程只发生一次;后续再 new 多少次对象,静态部分都不会重跑
- 注意:static final 基本类型常量(如 static final int PORT = 8080;)不触发类初始化,它的值已被编译器内联
实例部分:每次 new 都是一次完整流水线,自顶向下进入、自底向上返回
构造一个子类对象,本质是递归展开的过程:父类构造器必须完全执行完,子类才能开始自己的实例初始化。
- 父类实例变量默认值 → 父类实例变量赋值 + 构造块(从上到下)→ 父类构造函数体
- 子类实例变量默认值 → 子类实例变量赋值 + 构造块(从上到下)→ 子类构造函数体
- super() 是隐式或显式的首条语句,它把控制权交给父类构造流程;父类构造结束,才回到子类继续
- 构造块里别调用可被重写的方法——此时子类字段还没赋值,容易读到 0 或 null
用日志锚定每个环节,一眼看清执行流
靠记忆或推测容易出错,直接在关键位置加带标识的输出,是最可靠的验证方式。
- 在每个构造块开头打上 [I] Parent 或 [I] Child
- 在每个构造函数第一行写 [C] Parent() 或 [C] Child()
- 在成员变量初始化表达式里(如 String s = init();),也在 init() 方法内部加日志
- 理想输出应严格匹配:S-P → S-C → I-P → C-P → I-C → C-C(S=静态,I=实例,C=构造,P=父,C=子)
避开常见陷阱:不报错但状态错乱的地方
很多问题不会编译失败,却导致 NPE、默认值误用或死锁,根源常在初始化顺序被干扰。
- 静态块里访问子类尚未声明的静态字段?→ 把依赖字段移到前面声明,或改用 Holder 模式延迟初始化
- 父类构造器中调用了子类重写的方法?→ 此时子类实例变量全为默认值,极易空指针;应把复杂逻辑后移到 init() 方法或 final 方法中
- 多个静态块之间有隐式依赖?→ 按文本顺序执行,谁在前谁先跑;不要指望“后面块能覆盖前面逻辑”
- 静态块抛出未捕获异常?→ 类进入“初始化失败”状态,之后所有对该类的主动使用都会抛出 ExceptionInInitializerError
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











