Java子类访问父类变量返回null:显式调用父类构造仍取值为null
问题根因
当前实现方式不可行,核心是Java类初始化、实例构造的执行时序完全错配,和要不要使用Getter/Setter没有任何关系。
实际执行流程拆解
你代码的运行顺序和你的预期完全相反,具体节点如下:
- JVM启动时定位到
Child类的main方法入口,首先触发Child类的加载与初始化流程 - Child类初始化阶段会按定义顺序执行所有静态字段的赋值操作,此时执行
static final String parentName = Parent.name;:- 这一步执行时,
Parent类还未被触发初始化,也没有任何Parent类的实例被创建,Parent.name作为引用类型字段,JVM会给默认初始值null,这个null值会被永久固定为parentName的初始取值
- 这一步执行时,
- 等Child类初始化完成,才进入main方法的实际执行逻辑:
- 执行
new Child()时,才会向上追溯触发父类Parent的构造方法调用,打印"Parent constructor is called",把Parent.name的值赋值为"Adam"
- 执行
- 最后执行打印操作时,
parentName早在类初始化阶段就已经绑定了null值,不会随着Parent.name的后续修改发生变化,最终输出null
常见认知澄清
- 不需要强制依赖Getter/Setter才能读取父类变量。只要保证读取动作的发生时机在父类构造完成之后,不管是直接访问public修饰的父类变量,还是调用Getter方法,都能正常拿到赋值后的值
- 额外注意:
static final修饰的字段,如果取值不是编译期可确定的常量(比如这里的Parent.name是运行时才能拿到的值),只会在类初始化阶段执行一次赋值,后续不会重新计算取值,这也是parentName始终保持null的直接原因
调整方向
- 不要在子类的静态初始化阶段,直接读取需要靠父类构造才能完成赋值的变量。把读取动作移到实际使用的场景下:比如在main方法内直接打印
Parent.name,或者把parentName从静态字段改成实例字段,在父类构造执行完成后再触发赋值 - 如果本意是要读取父类的实例成员变量(而非当前代码里的静态类变量),只要父类构造正常执行,子类在实例方法、实例字段上下文里直接访问即可,不需要额外编写Getter/Setter
内容的提问来源于stack exchange,提问作者Steven.Q
相关产品推荐
相关产品推荐

