为什么静态字段没有及时初始化?

以下代码仅打印null一次。


class MyClass {

   private static MyClass myClass = new MyClass();

   private static final Object obj = new Object();

   public MyClass() {

      System.out.println(obj);

   }

   public static void main(String[] args) {}

}

为什么在构造函数运行之前不初始化静态对象?


更新资料


我只是在没有注意的情况下复制了这个示例程序,我以为我们在谈论2个Object字段,现在我看到第一个是MyClass字段..:/


MM们
浏览 440回答 3
3回答

慕尼黑8549860

因为静态元素是按照在源代码中给出的顺序进行初始化的。看一下这个:class MyClass {  private static MyClass myClass = new MyClass();  private static MyClass myClass2 = new MyClass();  public MyClass() {    System.out.println(myClass);    System.out.println(myClass2);  }}那将打印:nullnullmyClassObjectnull编辑好吧,让我们更清楚一点。静态函数按照源代码中声明的顺序一一初始化。由于第一个静态字段在其余字段之前进行了初始化,因此在其初始化期间,其余静态字段为null或默认值。在第二个静态变量的初始化期间,第一个静态变量是正确的,但其余的仍为null或默认值。明白了吗?编辑2正如Varman指出的那样,在初始化时对其自身的引用将为null。如果考虑一下,这是有道理的

万千封印

让我们尝试另一种方式来解释这一点...这是您首次引用该类时JVM经历的顺序MyClass。将字节码加载到内存中。清除了用于静态存储的内存(二进制零)。初始化类:按照显示顺序执行每个静态初始化程序,其中包括静态变量和static { ... }块。然后,JVM将您的myClass静态变量初始化为的新实例MyClass。发生这种情况时,JVM会注意到MyClass已加载(字节码)并且正在初始化,因此它会跳过初始化。在堆上为对象分配内存。执行构造函数。打印出obj仍然是静态的值null(因为它不是堆和构造函数初始化变量的一部分)。构造函数完成后,执行下一个静态初始值设定项obj,将其设置为的新实例Object。类初始化完成。从这一点来看,所有构造函数调用都将按照您的假定/期望的方式运行-这obj将不仅仅是null对Object实例的引用。请记住,Java指定给final变量分配一次值。并不是确保在代码引用它时为它分配一个值,除非您确保在赋值后代码引用了它。这不是错误。这是在类自身初始化期间处理类使用的已定义方法。如果不是这样,那么JVM将陷入无限循环。请参阅步骤#3.3(如果JVM不跳过正在初始化过程中的类的初始化,它将继续对其进行初始化-无限循环)。还要注意,这一切都发生在首先引用该类的同一线程上。其次,JVM保证初始化将在允许任何其他线程使用此类之前完成。

HUWWW

这是因为Java按照声明的顺序执行静态部分。在您的情况下,顺序为新的MyClass新对象执行#1时,obj仍未初始化,因此它输出null。尝试以下操作,您将看到区别:class MyClass {  private static final Object obj = new Object();  private static MyClass myClass = new MyClass();  public MyClass() {    System.out.println(obj); // will print null once  }}一般来说,最好避免一起使用这种构造。如果您尝试创建一个单例,那么该代码片段应如下所示:class MyClass {  private static final MyClass myClass = new MyClass();  private Object obj = new Object();  private MyClass() {    System.out.println(obj); // will print null once  }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java