一、 静态代码块 (Static Block)
-
格式
javastatic { // 初始化逻辑 } -
执行时机与顺序
- 在类加载到内存的"初始化阶段"执行
- 优先于实例代码块和构造器执行
- 若存在多个静态代码块,按照在代码中定义的先后顺序依次执行
- 父类的静态代码块优先于子类的静态代码块执行
-
作用与典型应用场景
- 对静态成员变量进行复杂初始化(无法通过简单赋值完成时)
- 加载配置文件、读取外部资源或建立数据库连接池等全局一次性操作
- 注册驱动(如JDBC中的
Class.forName旧式写法) - 执行仅需运行一次的校验或日志记录
-
注意事项
- 只能访问静态成员(静态变量、静态方法),不能直接访问实例成员
- 不能使用
this或super关键字 - 不能抛出受检异常(Checked Exception),除非在内部捕获处理;若发生未捕获的运行时异常,会导致类加载失败,抛出
ExceptionInInitializerError - 即使不创建对象,只要类被主动使用(如调用静态方法、访问静态字段),静态代码块也会执行
二、 实例代码块 (Instance Initializer Block)
-
格式
java{ // 初始化逻辑 } -
执行时机与顺序
- 每次调用构造器创建对象时执行
- 执行顺序:父类静态代码块 -> 子类静态代码块 -> 父类实例代码块 -> 父类构造器 -> 子类实例代码块 -> 子类构造器
- 若存在多个实例代码块,按照定义顺序依次执行
- 无论调用哪个重载构造器,实例代码块都会执行
-
作用与典型应用场景
- 提取多个构造器中的公共初始化逻辑,避免代码重复
- 对实例变量进行复杂初始化,尤其是当初始化逻辑相同但构造器参数不同时
- 在匿名内部类中执行初始化操作(因为匿名内部类没有命名构造器)
-
注意事项
- 可以访问静态成员和实例成员
- 可以使用
this关键字 - 不能抛出受检异常,除非在内部处理或在所有构造器的声明中都包含该异常
- 若仅在某个特定构造器中需要某段初始化逻辑,应直接写在构造器内,而非实例代码块中,以免在其他构造器调用时产生不必要的副作用
三、 完整执行顺序总结
假设存在继承关系,创建子类对象时的完整执行流程如下:
- 父类静态代码块(仅首次加载时)
- 子类静态代码块(仅首次加载时)
- 父类实例代码块
- 父类构造器
- 子类实例代码块
- 子类构造器
记忆口诀:静态先于实例,父类先于子类,代码块先于构造器
四、 对比总结表
| 特性 | 静态代码块 | 实例代码块 |
|---|---|---|
| 修饰符 | static | 无 |
| 执行次数 | 类生命周期内仅一次 | 每创建一个对象执行一次 |
| 执行时机 | 类加载初始化阶段 | 对象创建时,构造器之前 |
| 可访问成员 | 仅静态成员 | 静态成员 + 实例成员 |
| this/super | 不可用 | 可用 |
| 主要用途 | 类级别一次性初始化 | 对象级别公共初始化 / 匿名类初始化 |
五、 补充说明
- 局部代码块 :在方法内部定义的
{ },用于限制变量作用域,与方法内普通语句无异,现代Java开发中极少使用,了解即可 - 序列化场景:实例代码块在反序列化过程中不会被执行(反序列化不调用构造器),若依赖实例代码块进行关键初始化,需注意此行为差异
- 实践:优先使用显式构造器和静态工厂方法进行初始化,代码块仅在确实能减少重复代码或处理匿名类等特殊场景时使用,避免滥用导致代码可读性下降