You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中子类对象创建时机及构造期方法重写引发NPE的疑问

这是个非常经典的Java构造器陷阱问题,咱们一步步把它拆解明白:

一、SubClass对象到底什么时候创建?

当你执行new SubClass()的瞬间,JVM就已经为SubClass对象分配了内存空间——这时候这个对象已经存在了,只不过它的所有成员变量(包括继承自父类的)都会被先设置成默认值:比如引用类型默认是null,基本类型默认是0、false这类。构造器的作用只是把对象从“默认初始状态”改成“你想要的状态”,而不是等构造完才创建对象。

二、为什么父类构造器里调用foo()会触发子类的重写方法?

Java里的非私有方法调用是运行时动态绑定的:简单说,调用哪个版本的方法,看的是实际创建的对象类型,而不是代码里引用的声明类型。

在父类构造器执行时,虽然当前代码在SuperClass的构造逻辑里,但实际存在的对象是SubClass实例(因为你new的是SubClass)。所以当父类构造器调用foo()时,JVM会自动找到SubClass中重写的foo()方法去执行,而不是父类自己的版本——这就是方法重写在构造阶段依然生效的原因。

三、空指针异常到底怎么来的?

咱们把整个构造流程走一遍就清楚了:

  1. 执行new SubClass(),JVM分配SubClass对象内存,成员变量str被默认设为null
  2. 子类构造器里会隐式调用父类的无参构造super()(如果你没手动写,Java会自动加)
  3. 父类构造器执行foo(),因为动态绑定,实际调用的是SubClass的foo()
  4. SubClass的foo()里尝试调用str.toLowerCase(),但此时str还没被赋值(子类构造器里的str = "SubClass"要等父类构造完全执行完才会跑),所以str还是null,直接触发空指针异常
  5. 异常抛出后,子类构造器里的赋值代码根本没机会执行
四、如何避免这类坑?
  • 绝对不要在构造器里调用可被重写的方法(也就是非private、非final、非static的方法)
  • 如果父类构造需要执行初始化逻辑,把逻辑放到private或者final的方法里,这样子类无法重写,就不会出现动态绑定到子类方法的问题

内容的提问来源于stack exchange,提问作者Abhilash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:12:55