web-dev-qa-db-ja.com

静的変数はいつ初期化されますか?

静的変数がいつデフォルト値に初期化されるのか疑問に思っています。クラスがロードされたときに、静的変数が作成(割り当て)され、静的初期化子と宣言内の初期化が実行されるのは正しいですか?どの時点でデフォルト値が与えられますか?これは前方参照の問題につながります。

また、 なぜ静的フィールドが時間内に初期化されないのか? および特に同じサイトのKevin Brockが答えた質問を参照してこれを説明できるかどうかもお願いします。 3番目のポイントを理解できません。

72
Ankit

から Java静的変数メソッドを参照

  • これは、オブジェクトではなくクラスに属する変数です(インスタンス)
  • 静的変数は、実行の開始時に一度だけ初期化されます。これらの変数は、インスタンス変数の初期化の前に最初に初期化されます
  • クラスのすべてのインスタンスで共有される単一のコピー
  • 静的変数にはクラス名で直接アクセスでき、オブジェクトは必要ありません。

インスタンスおよびクラス(静的)変数は、意図的に初期化しないと、標準のデフォルト値に自動的に初期化されます。ローカル変数は自動的に初期化されませんが、ローカル変数の初期化に失敗したプログラムをコンパイルしたり、使用する前にそのローカル変数に値を割り当てたりすることはできません。

コンパイラが実際に行うことは、すべての静的変数初期化子とコードのすべての静的初期化子ブロックをクラス宣言に現れる順序で結合する単一のクラス初期化ルーチンを内部的に生成することです。この単一の初期化手順は、クラスが最初にロードされたときに一度だけ自動的に実行されます。

innerクラスの場合、静的フィールドを持つことはできません

内部クラスは、staticで明示的または暗黙的に宣言されていないネストされたクラスです。

...

内部クラスは、静的初期化子(§8.7)またはメンバーインターフェイスを宣言できません...

定数クラスでない限り、内部クラスは静的メンバーを宣言できません...

JLSを参照してください 8.1.3内部クラスとそれを囲むインスタンス

Javaのfinalフィールドは、宣言場所とは別に初期化できますが、これはstatic finalフィールドには適用できません。以下の例を参照してください。

final class Demo
{
    private final int x;
    private static final int z;  //must be initialized here.

    static 
    {
        z = 10;  //It can be initialized here.
    }

    public Demo(int x)
    {
        this.x=x;  //This is possible.
        //z=15; compiler-error - can not assign a value to a final variable z
    }
}

これは、インスタンス変数のようにタイプの各インスタンスに関連付けられたものではなく、タイプのstaticを初期化しようとすると、タイプに関連付けられたz変数が1つcopyしかないためですコンストラクター内のstatic finalは、静的zフィールドに発生してはならないクラスのインスタンス化ごとにコンストラクターが実行されるため、static final型フィールドfinalの再初期化を試みます。

60
Lion

見る:

特に最後は 詳細な初期化手順 を提供します。これは、静的変数が初期化されるときとその順序を示します(コンパイル時定数であるfinalクラス変数とインターフェースフィールドは最初に初期化されます。)

ポイント3についての具体的な質問(ネストされたものを意味すると仮定した場合)が何であるかわかりません。詳細なシーケンスでは、これは再帰的な初期化要求であるため、初期化が続行されます。

14
Dave Newton

静的フィールドは、クラスがクラスローダーによってロードされるときに初期化されます。この時点でデフォルト値が割り当てられます。これは、ソースコードに表示される順序で行われます。

8
Dave

初期化の順序は次のとおりです。

  1. 静的初期化ブロック
  2. インスタンス初期化ブロック
  3. コンストラクター

プロセスの詳細は、JVM 仕様 ドキュメントで説明されています。

7
Óscar López

静的変数

  • これは、object(instance)ではなくクラスに属する変数です
  • 静的変数は、実行の開始時(クラスローダーが初めてクラスをロードするとき)に1回だけ初期化されます。
  • これらの変数は、インスタンス変数の初期化の前に最初に初期化されます
  • クラスのすべてのインスタンスで共有される単一のコピー
  • 静的変数はクラス名から直接アクセスでき、オブジェクトは必要ありません
3
aleroot

他の質問のコードから始めます:

class MyClass {
  private static MyClass myClass = new MyClass();
  private static final Object obj = new Object();
  public MyClass() {
    System.out.println(obj); // will print null once
  }
}

このクラスへの参照は初期化を開始します。最初に、クラスは初期化済みとしてマークされます。次に、最初の静的フィールドがMyClass()の新しいインスタンスで初期化されます。 myClassには、すぐにblank MyClassインスタンスへの参照が与えられることに注意してください。スペースはありますが、すべての値はヌルです。コンストラクタが実行され、obj(null)が出力されます。

クラスの初期化に戻ります:objは新しい実オブジェクトへの参照になり、完了です。

これが次のようなステートメントによって相殺された場合:MyClass mc = new MyClass();新しいMyClassインスタンスのスペースが再び割り当てられます(そして、参照はmcに配置されます)。コンストラクターが再度実行され、objが再度出力されます。これはnowはnullではありません。

ここでの本当のトリックは、WhatEverItIs weii = new WhatEverItIs( p1, p2 );newのようにweiiを使用すると、すぐにNULLメモリーのビットへの参照が与えられることです。その後、JVMは値を初期化し、コンストラクターを実行します。ただし、何らかの方法でweiiを参照する場合beforeは、別のスレッドから参照するか、またはクラスの初期化から参照することにより、たとえば、満たされたクラスインスタンスを見ていますヌル値。

3
RalphChapin

静的変数は、次の3つの方法で初期化できます。

  1. 宣言時に初期化できます
  2. または、静的ブロックを作成することで実行できます。例:

    static {
            // whatever code is needed for initialization goes here
        }
    
  3. 静的ブロックに代わるものがあります—プライベート静的メソッドを書くことができます

    class name {
        public static varType myVar = initializeVar();
    
        private static varType initializeVar() {
            // initialization code goes here
        }
    }
    
3
ajay verma