我不明白为什么下面的代码不会导致堆(OutOfMemoryError 或其他东西)的堆栈溢出等价物,因为它是某种无限递归(不是吗?)。静态初始化是否提供了对此类事情的防范并引发 NullPointerException?
编辑:我不相信我被理解:
public static void main(String[] args)
从StaticClass
. doSmth()
在调用此方法之前,StaticClass
需要先加载。当一个类被加载时,所有的静态代码都会运行;在StaticClass
类中,objClass
是一个带有 a 值的静态字段new ObjClass()
,因此不应该是null
(抛出NullPointerException
)。显然new ObjClass()
不能实例化,因为为了做到这一点,你需要加载StaticClass
并且这在加载时已经发生StaticClass
(因此与无限递归的类比,或者可能是死锁类比)。问题是 JVM 说它是空的,而不是说它因为某种循环调用objClass
而无法初始化。new ObjClass()
在正常情况下,NullPointerException 因为调用者而被抛出。但是在这种情况下,您只能更改被调用者(在ObjClass
构造函数中删除末尾带有注释的行),然后您将不会收到NullPointerException
.
package pack;
public class ObjClass
{
public ObjClass() {
StaticClass.doSmth();//if removed, no NullPointerException
}
public String getSomething() {
return "get";
}
public static void main(String[] args) {
StaticClass.loadStaticClass();
}
}
class StaticClass {
private static ObjClass objClass = new ObjClass();
static void loadStaticClass() {
}
static void doSmth() {
System.out.println(objClass.getSomething());
}
}
这使:
Exception in thread "main" java.lang.ExceptionInInitializerError
at pack.ObjClass.main(ObjClass.java:28)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.lang.NullPointerException
at pack.ObjClass$StaticClass.doSmth(ObjClass.java:39)
at pack.ObjClass.<init>(ObjClass.java:20)
at pack.ObjClass$StaticClass.<clinit>(ObjClass.java:34)
... 6 more