在我的自定义初始值设定项可以启动之前,超类会引发异常



我有自己的类,它扩展了一个外部类,该类覆盖了一个外部类,使其文本始终为"Hello"。它看起来像:

import ext.ExternalClassA;
public class ClassB extends ExternalClassA {
    private String customText = "Hello";
    public ClassB() { // line 6
    }
    @Override
    public void setText(String newText) {
        return;
    }
    @Override
    public String getText() {
        return customText;
    }
}

然而,当我运行我的程序时,它崩溃了,并出现如下错误:

Exception in thread "main" java.lang.NullPointerException
    at ext.ExternalClassA.setup(ExternalClassA.java:123)
    at ext.ExternalClassA.<init>(ExternalClassA.java:45)
    at my.ClassB.<init>(ClassB.java:6)

当我看ExternalClassA.java时,我看到这个:

// imports...
public class ExternalClassA {
    private String text;
    // Other variables
    public ClassB() {
        text = "Default";
        setup(); // line 45
    }
    // more code...
    private void setup() {
        if (text == null)
            return;
        String textStr = getText().toString(); // line 123
        // more code...
    }
    // more code...
}

我做错了什么?我该怎么修理它?是外部类的问题吗?

问题是ExternalClassA试图使用其getText()方法来获取文本。从前面的几行代码来看,这应该是安全的。但是,不知道的是,您对getText()的重写并不总是返回text。这对您来说似乎很好,因为您使用的是customText,它被设置为"Hello"。然而 !在父类的初始化器退出之前,此赋值不会发生。下面是初始化的顺序:

只有一次

:

  1. 超类的静态变量
  2. 超类的静态构造函数
  3. this' s static variables
  4. this' static constructor

每个新对象:

<
  • 超类的变量/gh>
  • 超类的构造函数
  • <
  • 这种"变量/gh>
  • 这种"构造函数
  • 所以,当父类调用getText()时,它将进入您的父类。此时此刻,你的customTextnull,而superText"Default"

    这似乎是一个双赢,因为没有办法设置你的值之前,超类完成初始化,,但有一个解决方案!它位于相同的行为中。将customText默认为null的Java机制也将原语默认为0false。我们可以这样修改ClassB:

    import ext.ExternalClassA;
    public class ClassB extends ExternalClassA {
        private String customText = "Hello";
        private boolean hasStarted = true;
        public ClassB() {
        }
        @Override
        public void setText(String newText) {
            return;
        }
        @Override
        public String getText() {
            if (!hasStarted)
                return super.getText();
            return customText;
        }
    }
    

    注意hasStarted只有在父类的构造函数返回后才会变成true

    tl;博士


    我做错了什么?

    在构造函数控制之前,您不知道初始化时的操作顺序会导致字符串为null

    我该如何修复它?

    在超类初始化期间回退到超类方法。

    是外部类的问题吗?

    是的,父类不应该检查变量以假定方法的返回值

    你应该重写setup:

    public void setup() {
        setText("Hello");
        super.setup();
    }
    

    然后你可以把你所有的东西从b班放下。

    最新更新