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です)
次に、行に移動して
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 メソッドが呼び出されます。

問題のクラスには、値を代入する静的フィールドがあります。フィールドは静的であるため、クラスを任意のコンテキストで使用する前に初期化する必要があります。つまり、値を受け取る必要があります。この場合、その値はたまたま同じクラスのインスタンスになります。これは、クラスの初期化中にプライベート コンストラクターをトリガーするものです。

プロセスを詳しく調べて理解を深めたい場合は、Java Laguage Specificationを参照してください。より具体的には、セクション12.4クラスとインターフェースの初期化で詳細を確認できます。

于 2012-10-24T14:02:34.010 に答える
3

クラスは、最初に JVM のクラスローダーによってロードおよび初期化されます。そして、JVMは初期化中にクラス(Singleton)をスキャンし、その間に最初の行にある静的変数を初期化します。その変数はコンストラクターを呼び出し、その中に行を出力します。クラスが初期化されると、main メソッドが呼び出されるため、その中にステートメントが出力されます。

于 2012-10-24T14:12:51.307 に答える
2

static フィールドを初期化する必要があるため、このnew Singleton()ステートメントが最初に実行されます。currentSingletonこれは、作成される Singleton オブジェクトのメモリが割り当てられ、結果のオブジェクトをフィールド変数に割り当てる前にそのコンストラクタが実行されることを意味します。これがSystem.out.println("Singleton private constructor...");、割り当ての前に行が実行される理由です。さらに、クラスが参照されるとすぐに静的フィールドの初期化が発生し、Singleton クラスのメイン関数を呼び出すことはそれを参照することを意味します。これが、メイン メソッドの前に初期化が実行される理由です。

于 2012-10-24T14:29:43.017 に答える
2

コントロールが main() メソッドに到達する前に、クラスを初期化する必要があります。currentSingletoninline with 宣言を初期化するため、この初期化はクラスのロード中に main() の前に行われます。

于 2012-10-24T14:03:15.230 に答える
2

むしろ次のように宣言する必要がありますfinal

private static final Singleton currentSingleton = new Singleton();
  1. final クラス変数と、値がコンパイル時の定数であるインターフェイスのフィールドが初期化されます

JLS#8.3.2からの両方の質問への回答。フィールドの初期化

宣言子がクラス変数 (つまり、静的フィールド) 用である場合、変数初期化子が評価され、クラスが初期化されるときに 1 回だけ割り当てが実行されます (§12.4.2)。

于 2012-10-24T14:03:39.770 に答える