商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > 如何通过代码块执行顺序实战掌握子类对父类构造块逻辑的隐式继承

如何通过代码块执行顺序实战掌握子类对父类构造块逻辑的隐式继承

  发布于2026-07-02 阅读(0)

扫一扫,手机访问

很多人学Ja va继承的时候,都背过"父类静态块→子类静态块→父类普通块→父类构造器→子类普通块→子类构造器"这个顺序。但说实话,光背口诀没什么用,真正要理解它,你得让代码替你说话——每次new对象时,JVM都在后台默默执行一套固定的流水线。关键不在于"记住顺序",而在于搞清楚这个顺序为什么不能乱、容易在哪儿翻车、以及怎么用最少的代码把它验证出来。

如何通过代码块执行顺序实战掌握子类对父类构造块逻辑的隐式继承

静态代码块:类加载阶段的"一次性入场券"

静态代码块是跟着类走的,跟具体的对象实例没关系。只要JVM第一次主动用到了某个类——比如通过new创建对象、调用它的静态方法、或者访问它的静态字段——就会触发类加载和初始化。这时候执行顺序有两层含义:

  • 父类的静态初始化永远优先于子类,这是递归保障的
  • 同一个类里的多个静态块,按代码里写的顺序依次执行

一旦某个类的静态块执行完毕,后续不管new多少个对象,它都不会再跑第二遍。想验证这一点很简单:在父类和子类里各写一个带打印语句的静态块,然后在main方法里先调用一下子类的静态方法(注意不要new对象),再new一个子类实例。你会看到,静态块的输出只出现一次,而且父类的输出一定排在子类前面。

普通代码块与构造器:每次new都走一遍的"初始化流水线"

非静态的{}块(也就是普通代码块)是跟着实例走的。每次创建对象,它都会执行,而且位置是固定的——在对应的构造器体执行之前、super()调用完成之后。实际上,编译器会把普通代码块的代码直接插入到super()后面、构造器主体前面。完整的链路是:

  • 先给父类的字段分配内存并设为默认值(比如int就是0,Object就是null)
  • 执行父类的普通代码块(按声明顺序)
  • 执行父类构造器主体
  • 给子类的字段赋初始值(比如 int x = 5 这种)
  • 执行子类的普通代码块
  • 执行子类构造器主体

验证起来也不复杂:在父类和子类里都定义一些字段、各自写一个普通代码块和一个构造器,每个地方都加上System.out.println。注意,不要在子类构造器里显式写super(),让编译器自动帮你补上。跑起来看看输出顺序,你会清楚地看到"父类普通块→父类构造器→子类普通块→子类构造器"这条刚性链条,一步都不会乱。

隐式super()是理解继承初始化的核心开关

子类构造器的第一行,编译器永远会偷偷加一个super()调用,除非你显式写了this()或者super(...)。这可不是什么语法糖,而是JVM强制保证父类部分能被正确初始化的底层机制。一旦父类没有无参构造器,而子类又没有显式调用super(...),编译阶段就会直接报错,没商量。

这里有一个很常见的坑:父类的构造器里调用了一个被子类重写的方法。这时候子类的字段很可能还是默认值(null或者0),因为子类的普通代码块和字段的显式初始化还没走到那一步。这就是典型的"过早暴露未初始化状态"问题。

想亲眼看看这个坑长什么样?可以在父类构造器里调用一个普通的虚方法(比如叫init()),然后在子类里重写这个方法,在里面打印一下子类的某个字段。运行后你会发现,打印出来的是null——这不是bug,而是隐式调用链加上初始化阶段分离导致的必然结果,属于设计层面的约束。

用最小差异对比法锁定执行逻辑

不要为了验证这个顺序去写一个大项目,两个类加三行main方法就足够了。可以分三步走:

第一步,让父类有静态块、普通块和构造器,子类只写普通块和构造器,看看基础链路对不对。第二步,把父类的无参构造器删掉,加一个有参构造器,子类不写super(...),编译会直接失败——你马上就明白了隐式调用的硬性约束。第三步,在子类构造器第一行显式写上super(123),再加一句打印,确认super()确实是第一句执行的内容。

这种"改一行代码、跑一次程序、看一眼输出"的方式,比读十遍技术文档都管用。执行顺序说到底不是抽象概念,它就是stdout里逐行出现的那几行打印结果。

本文转载于:https://www.php.cn/faq/2465218.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注