我有自己的类,它扩展了一个外部类,该类覆盖了一个外部类,使其文本始终为"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"
。然而 !在父类的初始化器退出之前,此赋值不会发生。下面是初始化的顺序:
:
- 超类的静态变量
- 超类的静态构造函数
- this' s static variables
- this' static constructor
每个新对象:
- <
- 超类的变量/gh>
- 超类的构造函数 <
- 这种"变量/gh>
- 这种"构造函数
所以,当父类调用getText()
时,它将进入您的父类。此时此刻,你的customText
是null
,而superText
是"Default"
。
这似乎是一个双赢,因为没有办法设置你的值之前,超类完成初始化,,但有一个解决方案!它位于相同的行为中。将customText
默认为null
的Java机制也将原语默认为0
或false
。我们可以这样修改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班放下。