我遇到以下程序的问题,它有两个类A和B,一个方法getObject()在A类中已经在B类中重写,B类扩展了A类。
我从基类构造函数中调用getObject(),我相信它会在类B中调用重写方法,并且在运行时错误是空指针异常,为什么Object尚未初始化,即使它有?
class A {
Object object = new Object();
public A() {
System.out.println("A Class");
getObject();
}
public void getObject() {
System.out.println("Class A Version");
System.out.println(object.toString());
}
}
class B extends A {
Object object = new Object();
public B() {
System.out.println("B Class");
}
@Override
public void getObject() {
System.out.println("Class B Version");
System.out.println(object.toString());
}
}
public class Init {
public static void main(String[] args) {
new B();
}
}
输出
A Class
Exception in thread "main" Class B Version
java.lang.NullPointerException
at net.mindview.util.B.getObject(Init.java:28)
at net.mindview.util.A.<init>(Init.java:8)
at net.mindview.util.B.<init>(Init.java:21)
at net.mindview.util.Init.main(Init.java:34)
答案 0 :(得分:4)
根据this answer:
正确的初始化顺序是:
- 静态变量初始化和静态初始化块,按文本顺序排列,如果该类之前尚未初始化。
- 构造函数中的super()调用,无论是显式还是隐式。
- 实例变量初始化程序和实例初始化程序段,按文本顺序排列。
- super()之后的剩余构造函数体。
醇>请参阅Java虚拟机规范的第2.17.5-6节。
基本上,类object
中的B
在正在执行类A
的构造函数期间尚未初始化(第2点:隐式super()
调用)。
答案 1 :(得分:3)
在B构造函数中,您调用一个使用B&#39的getObject()的构造,该构造使用的不是来自B的初始化对象。 逐步使用调试器,您将看到流程。
答案 2 :(得分:2)
NPE来自班级本身,而不是object
。构造函数工作时,this
为空。
B
扩展了A
,因此插入了隐式super
构造函数调用。这会打印你的&#34; A Class&#34;但是,方法调用等同于this.getObject();
,this
为空。
答案 3 :(得分:1)
我认为这个问题的关键点在于你应该知道超类的构造函数(以防万一)将首先被调用。让我们假设A也扩展C的另一个条件,以防c的构造函数首先被调用。
所以调用的顺序应该是:1个C的构造函数,2个构造函数A,最后是B的构造函数。
对于您的情况,因为首先调用了构造函数A,此时对象尚未初始化,导致空指针除外
答案 4 :(得分:1)
执行命令是:
class A {
Object object = new Object(); // --------------- 2
public A() {
System.out.println("A Class"); // ---------- 3
getObject(); // ---------------------------- 4 (calls B.getObject())
}
public void getObject() {
System.out.println("Class A Version");
System.out.println(object.toString());
}
}
class B extends A {
Object object = new Object(); // --------------- 7 (not executed)
public B() {
System.out.println("B Class"); // ---------- 8 (not executed)
}
@Override
public void getObject() {
System.out.println("Class B Version"); // -- 5
System.out.println(object.toString()); // -- 6 (exception!)
}
}
public class Init {
public static void main(String[] args) {
new B(); // ------------------------------- 1
}
}
答案 5 :(得分:1)
你永远不应该在构造函数中调用overridable方法,因为它引入了调用方法的歧义。在你的情况下,你的超级A调用B的getObject()。此时B点尚未实例化,因此呼叫失败并为您提供NPE。