我有一个抽象类和一个派生类。 查看提供的代码:-
public abstract class Parent{
public Parent(){
init();
}
public abstract void init();
}
public class Child extends Parent{
private String mTitle = null;
public Child(){
super();
System.out.println(mTitle.toString());
}
public void init(){
mTitle = "It' a test";
}
}
当我执行上面的代码时,它会在打印 mTitle 的值时抛出 NullPointerException。 如果您检查父类的构造函数中的代码,我调用了抽象方法,该方法将调用派生类的 init 方法, 在抽象方法中,我将 mTitle 值的值初始化为 ="It's a test";
调用父构造函数后派生类必须调用System.out.println。
如果它是这样做的,那么为什么它会抛出 NullPointerException。
但是,如果我只是离开 mTitle 的分配,它不会抛出异常,如:-
private String mTitle;
如果在调用类的结构时发生变量的初始化,并且我们知道默认情况下全局对象已初始化为空。 但是在这种情况下它不会抛出异常。
最佳答案
如 JLS §12.5 (Creation of New Class Instances)创建实例时使用以下过程:
将构造函数的参数分配给此构造函数调用新创建的参数变量。
如果此构造函数以对同一类中的另一个构造函数的显式构造函数调用(第 8.8.7.1 节)开始(使用 this),则评估参数并使用这五个相同的步骤递归地处理该构造函数调用。如果该构造函数调用突然完成,则此过程出于相同原因而突然完成;否则,继续第 5 步。
此构造函数不是以显式调用同一类中的另一个构造函数开始的(使用 this)。如果此构造函数用于 Object 以外的类,则此构造函数将以显式或隐式调用父类(super class)构造函数(使用 super)开始。使用这五个相同的步骤递归地评估父类(super class)构造函数调用的参数和过程。如果该构造函数调用突然完成,则此过程出于相同的原因突然完成。否则,继续第 4 步。
执行这个类的实例初始化器和实例变量初始化器,将实例变量初始化器的值分配给相应的实例变量,按照它们在源代码中出现的从左到右的顺序排列类(class)。如果执行这些初始化程序中的任何一个导致异常,则不会处理更多初始化程序,并且此过程会突然完成相同的异常。否则,继续第 5 步。
执行此构造函数的其余部分。如果该执行突然完成,则此过程出于同样的原因突然完成。否则,此过程正常完成。
这意味着您对 super()
的调用以及对被覆盖的 init()
方法的后续调用都在实例变量之前完成用 null
初始化,它丢弃 init
方法的结果并用 null
覆盖分配给 mTitle
的任何值> 值(value)。
这导致了以下黄金法则:永远不要在构造函数中调用非最终的、非私有(private)的方法!
关于java - 为什么是 NullPointerException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26827244/