static代码块在类首次加载时执行一次,顺序为父类静态内容→子类静态内容→父类实例内容→子类实例内容;用于一次性初始化、静态常量复杂赋值、类校验及饿汉式单例。

掌握 static 关键字在类加载过程中的执行顺序,关键不是死记硬背,而是理解“类加载时机”和“静态内容生命周期”这两个底层逻辑。静态代码块不是随便写的,它只在类第一次被 JVM 加载时执行一次,之后无论 new 多少对象,都不会再触发。
类加载时的静态执行顺序(含父子类)
当执行 new Child() 时,JVM 触发类加载流程,执行顺序严格遵循以下层级与先后关系:
- 父类静态内容先于子类执行:包括父类的静态变量赋值语句、静态代码块,按代码自上而下的顺序依次执行;
- 子类静态内容随后执行:同样按定义顺序,静态变量初始化 → 静态代码块;
- 静态执行完毕后,才开始非静态部分:即父类实例变量赋值 → 父类实例代码块 → 父类构造方法 → 子类实例变量赋值 → 子类实例代码块 → 子类构造方法。
注意:同一类中多个 static{} 块,或静态变量带初始化表达式(如 private static int a = initA();),都算作“静态内容”,统一按出现顺序执行。
静态代码块的典型应用场景
它不是语法装饰,而是为解决特定问题设计的机制。常用在以下几类需求中:
- 一次性资源初始化:比如读取配置文件、建立数据库连接池、加载本地库(System.loadLibrary),这些操作开销大且无需重复执行;
- 静态常量的复杂初始化:当 public static final 的值不能直接用字面量赋值(如需解析 JSON、计算哈希、查表生成),就放在 static 块里完成;
- 类级别的预校验或约束检查:例如验证运行环境、检查必要系统属性是否设置,若不满足可直接抛出 ExceptionInInitializerError 阻止类加载;
- 单例的“饿汉式”实例化:在 static 块中 new 实例并赋给 private static 字段,确保线程安全且类加载即就绪。
容易踩坑的关键细节
很多问题源于混淆了“静态”和“实例”的存在前提:
- 静态方法/代码块里不能访问 this、super,也不能调用非静态方法或读写非静态字段——因为此时对象还没造出来,那些成员根本不存在;
- 静态变量被所有实例共享:修改一个对象的 ClassName.staticField,等于修改了整个类的状态,其他对象立刻可见;
- 类加载不一定发生在 new 的那一刻:通过 Class.forName("X")、访问静态字段、调用静态方法等,只要首次主动使用该类,就会触发加载和静态执行;
- static 块中抛出异常会导致类初始化失败,后续任何对该类的引用都会抛 NoClassDefFoundError(不是 ClassNotFoundException)。
把 static 当作“类启动时自动运行的一次性 setup 脚本”,而不是“每次创建对象都要跑的初始化逻辑”,思路就清晰了。它不难,但必须和类加载机制一起看,脱离上下文就容易误用。










