0

0

Java中的类初始化:初始化子类时父类初始化的递归逻辑

P粉602998670

P粉602998670

发布时间:2026-02-25 00:05:35

|

170人浏览过

|

来源于php中文网

原创

不一定。父类static{}块仅在子类初始化时直接或间接引用父类静态成员且父类未初始化时才执行;构造器中的super()调用才保证父类构造器先于子类执行。

java中的类初始化:初始化子类时父类初始化的递归逻辑

子类构造时父类 <clinit></clinit> 一定先执行吗?

不一定。Java 类初始化(即执行 <clinit></clinit> 方法)是懒触发、单次、线程安全的,只在**首次主动使用该类时**发生。子类初始化不自动触发父类初始化——除非父类的某个静态成员被直接引用,或父类尚未初始化而子类的 <clinit></clinit> 中隐式依赖它(比如调用父类静态方法、访问父类静态字段等)。

常见错误现象:ExceptionInInitializerError 报在父类静态块里,但堆栈显示是从子类 new 或静态字段访问开始的——这说明父类初始化被“捎带”触发了,而非构造器本身驱动。

  • 只有当父类 <clinit></clinit> 尚未执行,且子类初始化过程**直接或间接引用了父类的静态成员**,JVM 才会先去执行父类 <clinit></clinit>
  • 如果父类已初始化过,子类初始化时完全跳过父类 <clinit></clinit>
  • 父类构造器(<init></init>)才是在子类构造器中显式/隐式 super() 调用时执行的,和 <clinit></clinit> 是两套机制

static {} 块在继承链中怎么触发?

每个类的 static {} 块只属于它自己的 <clinit></clinit>,不会被继承,也不会因子类初始化而“连带执行”,除非 JVM 主动加载并初始化该类。

使用场景:你写了一个 Base 类含 static { System.out.println("Base init"); },又写 Child extends Base,然后运行 new Child() —— 输出不一定有 "Base init",取决于 Base 是否已被初始化过。

立即学习Java免费学习笔记(深入)”;

拾贝
拾贝

一键同步微信读书所有笔记和划线,并在新标签页回顾

下载
  • 若此前从未访问过 Base 的任何静态字段或方法,new Child() 会触发 Base.<clinit></clinit>(因为子类符号引用了父类,且父类未初始化)
  • 若之前执行过 Base.SOME_STATIC_FIELD,那 new Child() 不再触发 Base.<clinit></clinit>
  • 若子类自己没定义 static{},它的 <clinit></clinit> 可能为空,但仍算作一次“类初始化事件”

为什么 Class.forName("Child")new Child() 初始化行为不同?

关键在参数:Class.forName(String) 默认调用的是 Class.forName(String, boolean, ClassLoader) 的重载版本,其中第二个参数为 true,表示“初始化该类”。而 new 触发的是“类加载 + 链式初始化判断”,逻辑更精细。

性能影响:Class.forName("Child") 会强制初始化 Child 及其尚未初始化的、被直接引用的父类(如 Base 的静态字段出现在 Child.<clinit></clinit> 中),但不会无脑初始化整个继承树顶层的所有祖先。

  • Class.forName("Child") → 触发 Child.<clinit></clinit>(以及必要时的父类 <clinit></clinit>
  • Class.forName("Child", false, loader) → 只加载,不初始化,此时 Child.<clinit></clinit> 完全不执行
  • new Child() → 先确保 Child 类已加载,再按需决定是否初始化 Child 和父类,取决于它们是否已被初始化过

容易忽略的初始化顺序陷阱

最常踩的坑是把“类初始化”和“实例初始化”混为一谈,尤其在静态字段依赖子类实现、或静态块里调用可被重写的方法时。

示例:Basestatic final String NAME = getValue();,而 getValue() 是非 private / 非 static 方法,子类重写了它——这时 Base.<clinit></clinit> 执行期间会调用子类的 getValue(),但此时子类实例还没创建,字段可能为默认值(null0 等),导致 NPE 或逻辑错乱。

  • 静态上下文里永远不要调用可被子类重写(即非 private / 非 static / 非 final)的方法
  • 避免在父类静态字段初始化表达式中强依赖子类状态
  • 注意 enum 类的初始化:它的 <clinit></clinit> 会按声明顺序初始化所有枚举实例,且父类枚举的初始化早于子类枚举

复杂点在于:这个顺序不是写死的流程图,而是由字节码指令(getstaticldcnew)和类加载器的解析行为共同决定的,调试时得看 javap -c 输出的 <clinit></clinit> 指令流。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

850

2023.08.02

java中boolean的用法
java中boolean的用法

在Java中,boolean是一种基本数据类型,它只有两个可能的值:true和false。boolean类型经常用于条件测试,比如进行比较或者检查某个条件是否满足。想了解更多java中boolean的相关内容,可以阅读本专题下面的文章。

364

2023.11.13

java boolean类型
java boolean类型

本专题整合了java中boolean类型相关教程,阅读专题下面的文章了解更多详细内容。

40

2025.11.30

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

246

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

866

2024.03.01

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

246

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

866

2024.03.01

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

246

2023.09.22

Golang 生态工具与框架:扩展开发能力
Golang 生态工具与框架:扩展开发能力

《Golang 生态工具与框架》系统梳理 Go 语言在实际工程中的主流工具链与框架选型思路,涵盖 Web 框架、RPC 通信、依赖管理、测试工具、代码生成与项目结构设计等内容。通过真实项目场景解析不同工具的适用边界与组合方式,帮助开发者构建高效、可维护的 Go 工程体系,并提升团队协作与交付效率。

1

2026.02.24

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3.9万人学习

C# 教程
C# 教程

共94课时 | 10.1万人学习

Java 教程
Java 教程

共578课时 | 71.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号