3

我知道关于单例模式有很多问题。但是在这里我想知道关于输出的内容,它也可能涵盖“静态”在 Java 中的工作方式。

public class Singleton {
    private static Singleton currentSingleton = new Singleton();

    public static Singleton getSingleton() { 
        return currentSingleton;
    }

    private Singleton() {
        System.out.println("Singleton private constructor...");
    }

    public static void main(String[] args) {
        System.out.println("Main method...");
    }

    }

这是运行代码的输出...

单例私有构造函数...
主要方法...

当我调试这段代码时,控制首先进入 System.out.println("Singleton private constructor...")并打印。(此时私有静态变量currentSingleton仍为null)
然后进入line
private static Singleton currentSingleton = new Singleton(); ,然后初始化私有变量。最后,它转到 main() 方法并打印。

我的问题是:

  1. 为什么它首先打印私有构造函数中的“单例私有构造函数...”。我认为控制应该首先转到 main() 方法,因为它是入口点。此外,我没有在任何地方创建任何实例(变量初始化除外)。
  2. 后来到了静态变量实例化行(此时currentSingleton=null)
    private static Singleton currentSingleton = new Singleton(); 虽然currentSingleton在这里得到了一个值,但是为什么没有再次调用构造函数呢?

主要是想知道这个程序的控制流程。

4

6 回答 6

4

每当控制第一次进入任何类时,所有静态初始化都会首先发生。这就是为什么你的静态对象通过调用它的构造函数在其他任何东西之前被实例化。

于 2012-10-24T14:03:01.437 回答
3

您不能调用类中的 main 方法,直到它被正确初始化(即静态字段和静态块已被评估)。当它被初始化时,你的单例实例是通过调用私有构造函数来创建的。稍后调用 main 方法。

有问题的类有一个静态字段,您可以为其分配一个值。由于该字段是静态的,因此必须在类可以在任何上下文中使用之前对其进行初始化,也就是说,它必须接收一个值。在这种情况下,它的值恰好是同一类的一个实例。这是在类初始化期间触发您的私有构造函数的原因。

如果您想深入研究该过程并更好地理解它,请参阅Java Laguage 规范。更具体地说,在第 12.4 节类和接口的初始化中,您将找到更多详细信息。

于 2012-10-24T14:02:34.010 回答
3

类首先由 JVM 的类加载器加载和初始化。JVM 在初始化时扫描类(Singleton)并在这样做的同时初始化第一行中的静态变量。该变量调用构造函数并在其中打印行。一旦类被初始化,它将调用 main 方法并因此在其中打印语句。

于 2012-10-24T14:12:51.307 回答
2

在控件进入 main() 方法之前,需要初始化该类。由于您currentSingleton使用声明初始化内联,因此此初始化发生在 main() 之前,在类加载期间。

于 2012-10-24T14:03:15.230 回答
2

您应该将其声明为final

private static final Singleton currentSingleton = new Singleton();
  1. final 类变量和接口的字段,其值为编译时常量,被初始化

从JLS#8.3.2回答你的两个问题。字段的初始化

如果声明器用于类变量(即静态字段),则在初始化类时(第 12.4.2 节)评估变量初始化器并执行一次赋值。

于 2012-10-24T14:03:39.770 回答
2

new Singleton()语句首先被执行,因为currentSingleton必须初始化静态字段;这意味着为正在创建的 Singleton 对象分配内存,并在将结果对象分配给字段变量之前执行其构造函数。这是在System.out.println("Singleton private constructor...");分配之前执行该行的原因。此外,静态字段初始化在类被引用时立即发生,调用 Singleton 类的 main 函数意味着引用它,这就是在 main 方法之前执行初始化的原因。

于 2012-10-24T14:29:43.017 回答