Java 如果在类初始化期间调用重写的基方法,则不会初始化实例字段
有一个基类ServerAdapter:Java 如果在类初始化期间调用重写的基方法,则不会初始化实例字段,java,Java,有一个基类ServerAdapter: public class MyLinuxServerAdapter extends LinuxServerAdapter { public MyLinuxServerAdapter() { super(); } public static void main(String args[]) { ServerAdapter server = new MyLinuxServerAdapter();
public class MyLinuxServerAdapter extends LinuxServerAdapter {
public MyLinuxServerAdapter() {
super();
}
public static void main(String args[]) {
ServerAdapter server = new MyLinuxServerAdapter();
}
}
以及继承ServerAdapter的子类:
public class MyLinuxServerAdapter extends LinuxServerAdapter {
public MyLinuxServerAdapter() {
super();
}
public static void main(String args[]) {
ServerAdapter server = new MyLinuxServerAdapter();
}
}
继承LinuxServerAdapter的结束类:
public class MyLinuxServerAdapter extends LinuxServerAdapter {
public MyLinuxServerAdapter() {
super();
}
public static void main(String args[]) {
ServerAdapter server = new MyLinuxServerAdapter();
}
}
当我尝试在键上添加clickHandler时,会抛出NPE
为什么密钥没有初始化?这是初始化顺序以特定方式工作的情况吗?只需在init方法中初始化即可。这毕竟是目的
@Override
public void initGUI() {
key = new CheckBox();
key.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
//Something happens here
}
});
父类在子类之前实例化。在顶级父类中,您调用initGUI抽象方法,它的实现位于它的子类中,而它的其他字段尚未初始化。将字段的实际初始化移到initGUI方法是有意义的,它符合名称约定和您得到的逻辑。只需在init方法中初始化即可。这毕竟是目的
@Override
public void initGUI() {
key = new CheckBox();
key.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
//Something happens here
}
});
父类在子类之前实例化。在顶级父类中,您调用initGUI抽象方法,它的实现位于它的子类中,而它的其他字段尚未初始化。将字段的实际初始化移动到initGUI方法是有意义的,它符合名称约定和您得到的逻辑。实例变量声明中的赋值,以及类块中非静态块中的任何语句,都是在超级调用返回后运行的。如果从超类的构造函数调用子类的方法,它将使用未初始化的this
这就是为什么有一条一般规则,即永远不要从构造函数调用虚方法。实例变量声明中的赋值,以及类块中非静态块中的任何语句,都是在超级调用返回后运行的。如果从超类的构造函数调用子类的方法,它将使用未初始化的this
这就是为什么有一条一般规则,您永远不应该从构造函数调用虚拟方法。初始化顺序总是以特定的方式工作,JLS中详细介绍了这种方式。这就是为什么在构造过程中调用子类可能是粗略的一个原因。我猜initGUI是从基类调用的。你的类文本基本上是按调用顺序附加到基类末尾的。@JesanFafon你不必猜,它在第三行。哦,我明白了。首先,基类初始化发生,当我们调用在子类中实现的方法时,我们现在不调用该子类的c-tor。Hm.初始化顺序始终以特定方式工作,该方式在JLS中有详细说明。这就是为什么在构造过程中调用子类可能是粗略的一个原因。我猜initGUI是从基类调用的。你的类文本基本上是按调用顺序附加到基类末尾的。@JesanFafon你不必猜,它在第三行。哦,我明白了。首先,基类初始化发生,当我们调用在子类中实现的方法时,我们现在不调用该子类的c-tor。嗯。因此,避免这种情况的唯一方法是将所有字段初始化移动到initGUI实现中?这不是唯一的方法,而是更简单的方法。如果不是秘密,其他的变体是什么但无论如何,你的变体对我来说是好的。另一个可能的解决办法是使复选框保持静态。但是,这可能会产生其他问题,因为它将是所有实例之间的共享文件。另一个问题是将initGUI调用移动到实现了它的类LinuxServerAdapter。但我相信您希望从更高的级别执行调用,这是有意义的。因此,避免调用的唯一方法是将所有字段初始化移动到initGUI实现?这不是唯一的,但更简单。如果不是秘密,其他变体是什么但无论如何,你的变体对我来说是好的。另一个可能的解决办法是使复选框保持静态。但是,这可能会产生其他问题,因为它将是所有实例之间的共享文件。另一个问题是将initGUI调用移动到实现了它的类LinuxServerAdapter。但是我相信你想要从更高的层次上执行调用,这是有意义的。因此,为了避免违反规则,另一种方法是从子类c-tor调用virtual方法?因此,为了避免违反规则,另一种方法是从子类c-tor调用virtual方法?