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

Java中父类构造器修改的字段值为何会被重置?

问题分析:匿名内部类字段赋值后被重置的原因与解决

问题现象

你定义了三个类:

  • SuperClass:实现Runnable的抽象类,构造器中调用未实现的run()方法
  • ExtendingClass:继承SuperClass的抽象类,包含默认值为1的字段field,构造器调用父类构造器
  • 匿名内部类继承ExtendingClass并实现run()方法,将field改为2,但最终输出field的值是1,而run()内部输出的是2

代码示例

MainClass.java

package mainPackage;
public class MainClass {

    public MainClass() {
        ExtendingClass s=new ExtendingClass() {
            @Override
            public void run() {
                field=2;
                System.out.println(field);
            }
        };
        System.out.println(s.field);
    }

    public static void main(String[] args) {
        new MainClass();
    }

}

SuperClass.java

package mainPackage;

public abstract class SuperClass implements Runnable{
    public SuperClass() {
        run();
    }
}

ExtendingClass.java

package mainPackage;

public abstract class ExtendingClass extends SuperClass {
    int field=1;
    public ExtendingClass() {
        super();
    }

}

核心原因:Java对象初始化顺序

问题出在父类构造器调用子类重写方法时,子类实例变量尚未完成显式初始化,具体执行流程如下:

  1. 创建匿名内部类实例时,先触发父类ExtendingClass的构造器
  2. ExtendingClass构造器首先调用super(),进入SuperClass构造器
  3. SuperClass构造器调用run(),由于多态特性,实际执行的是匿名类的run()实现:将field赋值为2,此时控制台输出2
  4. SuperClass构造器执行完毕,回到ExtendingClass构造器,此时执行实例变量的显式初始化逻辑:int field=1;,这一步会把之前赋值的2覆盖为1
  5. 最终MainClass中输出s.field时,值已经被重置为1

解决方案

  1. 禁止在构造器中调用可重写的方法:这是Java开发的经典禁忌,因为子类对象在父类构造器执行时还未完成初始化,调用重写方法会导致不可预期的行为
  2. 改用初始化方法:将需要在对象创建后执行的逻辑放到一个单独的方法中,比如init(),在对象实例化后手动调用,而不是在构造器中触发
  3. 调整字段初始化时机:如果字段必须在构造阶段赋值,可以将字段的初始化逻辑放到构造器内部,而不是显式声明时赋值,这样可以避免被父类构造器执行后的初始化步骤覆盖

修正后的示例代码

比如修改ExtendingClass,将字段初始化放到构造器中,同时修改SuperClass不调用run(),而是提供初始化方法:

SuperClass.java

package mainPackage;

public abstract class SuperClass implements Runnable{
    public SuperClass() {
        // 不再在构造器中调用run()
    }

    // 提供初始化方法,在对象创建后调用
    public void initialize() {
        run();
    }
}

ExtendingClass.java

package mainPackage;

public abstract class ExtendingClass extends SuperClass {
    int field;
    public ExtendingClass() {
        super();
        // 构造器中初始化字段
        field=1;
    }
}

MainClass.java

package mainPackage;
public class MainClass {

    public MainClass() {
        ExtendingClass s=new ExtendingClass() {
            @Override
            public void run() {
                field=2;
                System.out.println(field);
            }
        };
        // 手动调用初始化方法
        s.initialize();
        System.out.println(s.field);
    }

    public static void main(String[] args) {
        new MainClass();
    }

}

此时输出会是两次2,符合预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 04:33:37