Java 类什么时候初始化?静态变量、静态代码块和构造方法按什么顺序执行?
下面是一段教学用的模拟面试。
🧑💻 面试官:Java 类什么时候初始化?
🙋♂️ 我:第一次使用的时候,会执行静态变量赋值和静态代码块。
🧑💻 面试官:读取一个 static final 常量,一定会初始化它所在的类吗?
🙋♂️ 我:编译期常量可能不会。
🧑💻 面试官:那通过子类名读取父类声明的静态字段呢?创建子类对象时,静态初始化和对象初始化又是什么顺序?
先区分「加载、链接、初始化」,再区分「类初始化」与「对象初始化」。不能把所有第一次接触都叫初始化。
面试速答(60 秒版)
Java 类的加载、链接和初始化是不同阶段。初始化主要执行静态字段的显式初始化和静态代码块,它们按源码顺序进行。
常见触发包括创建实例、调用类声明的静态方法、读取或写入类声明的非编译期常量静态字段,以及规定的反射调用。读取编译期常量,不一定触发声明类初始化。
初始化一个类之前,需要先初始化它的父类;涉及接口时还有默认方法等具体规则,不能说所有接口都按父类方式处理。
创建对象则是另一套过程。在传统的 super 首先执行的写法中,分配后先有默认值,然后沿构造链完成父类部分,再执行当前类实例字段赋值、实例初始化块和构造器的剩余主体。Java 25 还允许受限制的构造器前置代码,所以具体顺序也要看源码。静态初始化通常只发生一次,实例初始化则每个对象都要经历。

图:图中按传统的先调用 super、再执行当前类初始化来解释;Java 25 构造器前置语句的例外在下文单独说明。
知识点详解:先解释触发,再解释执行顺序
类已经加载,不代表静态代码块已经执行
假设程序需要使用配置类。JVM 可以先加载它的类信息,再进行验证、准备和解析等链接工作。
准备阶段涉及静态字段的初始默认值等处理;初始化才执行静态字段初始化表达式和静态代码块。final 常量还有规范中的特殊规则,所以不能把准备与初始化混成“一次给所有字段赋值”。
一些类查找或加载操作可以不触发初始化。判断时要看具体 API 的初始化参数,而不是看到 Class 对象就认定静态块已经运行。
主动使用,重点看字段或方法是谁声明的
创建某个类的对象,会触发这个类的初始化。调用静态方法、使用非编译期常量静态字段时,需要看它实际由哪个类声明。
假设 Base 声明静态字段,Child 继承 Base。即使通过 Child 这个名字访问该字段,也不能直接认为 Child 必须初始化;实际需要初始化的是字段的声明类。
编译期常量又是另一种情况。常量值可能被编入使用方,读取它不会因此触发声明类初始化。static final 不等于一定是编译期常量:如果值通过方法调用计算,就需要运行时求值。
触发条件和例外以 Java 语言规范第 12 章 为准。

图:访问写子类名,也要看声明类。
静态成员按源码顺序,但父类先完成
父类需要先初始化。之后当前类的静态字段初始化和静态块,再按源码排列顺序执行。
因此,静态块读取后面尚未完成显式初始化的字段,可能看到它当时的值,而不是最终值。实际写法还受到非法前向引用规则约束,不能凭想象编写任何顺序。
类初始化由 JVM 协调。如果两个线程同时触发,不会各自把同一个类的初始化完整执行一遍。初始化失败也会影响后续使用,不能简单当成“下次再执行一次”。
对象初始化,为什么不能把父子字段全部提前赋好?
先看传统的 super 首先执行的构造写法,也就是本文两张涉及对象构造顺序的图采用的情况。创建 Child 对象时,对象存储先有默认值,随后进入构造过程。父类的构造部分先完成;当前类的实例字段初始化和实例块,按源码顺序执行,然后才进入当前构造器的剩余主体。
如果构造器通过 this 委托给同类另一个构造器,还要沿委托链看执行位置。不要把“所有构造器都执行一次实例字段赋值”当成规则。
更危险的是父类构造器调用可覆盖方法:调用可能进入子类方法,但子类自己的字段初始化还没完成。此时读取到默认值,并不奇怪。因此,构造期间一般应避免向外泄露未完成对象或调用依赖子类状态的可覆盖方法。
不过,“父类构造器一定在子类所有语句之前执行”已经不能当成现代 Java 的通用规则。Java 25 正式引入了灵活构造器体,允许在显式 super 或 this 调用前执行受限制的前置代码,包括给当前类字段赋值。这样,父类构造器调用子类方法时,也可能已经读到前置段写入的值。具体限制见 JEP 513 和 JLS 12.5。因此,面试中说明常见顺序后,还要交代自己讨论的构造写法。
这里不提供 TypeScript/Python 示例,因为它们不能验证 Java 的构造与初始化规则。

图:这是传统构造器的执行次序,不覆盖 Java 25 允许的受限制前置语句。
面试官继续追问
创建两个对象,静态块执行两次吗?
同一个类身份成功初始化后,通常只初始化一次。两个对象各自执行实例初始化与构造,不会因此重复执行类初始化。
子类初始化,会初始化所有父接口吗?
不能这么概括。父类与接口的规则不同,类初始化还涉及声明默认方法的相关超接口。应说明具体声明,而不是套统一顺序。
为什么不要在静态块里做慢网络请求?
其他触发初始化的线程可能被阻塞,失败还会影响类可用性。耗时且易失败的外部依赖,最好采用明确的启动和重试生命周期。
面试速记卡
- 加载、链接、初始化:三个不同阶段。
- 触发:看主动使用及实际声明类。
- 编译期常量:读取不一定触发声明类初始化。
- 类初始化:父类先,当前类静态成员按源码顺序。
- 对象初始化:构造链、实例字段与构造器体另行分析。
公司面试真题
这道题暂未收录可核验的公司真题来源。你可以先阅读本文解析,或浏览已收录的公司面试真题。
浏览公司面试真题 →