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

静态代码块是跟着类走的,跟具体的对象实例没关系。只要JVM第一次主动用到了某个类——比如通过new创建对象、调用它的静态方法、或者访问它的静态字段——就会触发类加载和初始化。这时候执行顺序有两层含义:
一旦某个类的静态块执行完毕,后续不管new多少个对象,它都不会再跑第二遍。想验证这一点很简单:在父类和子类里各写一个带打印语句的静态块,然后在main方法里先调用一下子类的静态方法(注意不要new对象),再new一个子类实例。你会看到,静态块的输出只出现一次,而且父类的输出一定排在子类前面。
非静态的{}块(也就是普通代码块)是跟着实例走的。每次创建对象,它都会执行,而且位置是固定的——在对应的构造器体执行之前、super()调用完成之后。实际上,编译器会把普通代码块的代码直接插入到super()后面、构造器主体前面。完整的链路是:
验证起来也不复杂:在父类和子类里都定义一些字段、各自写一个普通代码块和一个构造器,每个地方都加上System.out.println。注意,不要在子类构造器里显式写super(),让编译器自动帮你补上。跑起来看看输出顺序,你会清楚地看到"父类普通块→父类构造器→子类普通块→子类构造器"这条刚性链条,一步都不会乱。
子类构造器的第一行,编译器永远会偷偷加一个super()调用,除非你显式写了this()或者super(...)。这可不是什么语法糖,而是JVM强制保证父类部分能被正确初始化的底层机制。一旦父类没有无参构造器,而子类又没有显式调用super(...),编译阶段就会直接报错,没商量。
这里有一个很常见的坑:父类的构造器里调用了一个被子类重写的方法。这时候子类的字段很可能还是默认值(null或者0),因为子类的普通代码块和字段的显式初始化还没走到那一步。这就是典型的"过早暴露未初始化状态"问题。
想亲眼看看这个坑长什么样?可以在父类构造器里调用一个普通的虚方法(比如叫init()),然后在子类里重写这个方法,在里面打印一下子类的某个字段。运行后你会发现,打印出来的是null——这不是bug,而是隐式调用链加上初始化阶段分离导致的必然结果,属于设计层面的约束。
不要为了验证这个顺序去写一个大项目,两个类加三行main方法就足够了。可以分三步走:
第一步,让父类有静态块、普通块和构造器,子类只写普通块和构造器,看看基础链路对不对。第二步,把父类的无参构造器删掉,加一个有参构造器,子类不写super(...),编译会直接失败——你马上就明白了隐式调用的硬性约束。第三步,在子类构造器第一行显式写上super(123),再加一句打印,确认super()确实是第一句执行的内容。
这种"改一行代码、跑一次程序、看一眼输出"的方式,比读十遍技术文档都管用。执行顺序说到底不是抽象概念,它就是stdout里逐行出现的那几行打印结果。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8