web-dev-qa-db-ja.com

Javaの静的ブロックの必要性

Javaにはstatic blockという機能があり、クラスが最初にロードされたときに実行されるコードが含まれていることがわかりました(「ロード」の意味がわかりません。初期化を意味しますか?)。コンストラクターではなく静的ブロック内で初期化ビットを実行する理由はありますか?つまり、コンストラクターも同じことを行い、クラスが最初に初期化されるときに必要なすべてのことを行います。コンストラクターができない静的ブロックで達成できることはありますか?

45
SexyBeast

クラスに複雑な初期化が必要な静的メンバーがある場合、staticブロックが使用するツールです。何らかの静的マップが必要であると仮定します(目的はここでは関係ありません)。次のようにインラインで宣言できます。

public static final Map<String, String> initials = new HashMap<String, String>();

ただし、一度移入したい場合は、インライン宣言でそれを行うことはできません。そのためには、staticブロックが必要です。

public static final Map<String, String> initials = new HashMap<String, String>();
static {
    initials.put("AEN", "Alfred E. Newman");
    // etc.
}

さらに保護したい場合、これを行うことができます:

public static final Map<String, String> initials;
static {
    HashMap<String, String> map = new HashMap<String, String>()
    map.put("AEN", "Alfred E. Newman");
    // etc.
    initials = Collections.unmodifiableMap(map);
}

initialsをインラインで変更できないマップとして初期化することはできないことに注意してください。そうすると、マップを設定できません。変更メソッド(putなど)の1つを呼び出すだけで例外が生成されるため、コンストラクターでこれを行うこともできません。

公平を期すために、これはあなたの質問に対する完全な答えではありません。 staticブロックは、プライベートの静的関数を使用することで依然として排除できます。

public static final Map<String, String> initials = makeInitials();

private static Map<String, String> makeInitials() {
    HashMap<String, String> map = new HashMap<String, String>()
    map.put("AEN", "Alfred E. Newman");
    // etc.
    return Collections.unmodifiableMap(map);
}

ただし、これはstaticブロックを、提案したコンストラクター内のコードに置き換えていないことに注意してください!

staticブロックを置き換えるのが面倒な場合は、他のいくつかのクラスを一度だけ初期化する必要がある「マスター」クラスになります。

public class Master {
    static {
        SlaveClass1.init();
        SlaveClass2.init(SlaveClass1.someInitializedValue);
        // etc.
    }
}

特に、SlaveClass2SlaveClass1への依存関係を固定したくない場合は、このような何らかのマスターコードが必要です。この種のものは、間違いなくコンストラクターに属していません。

instance initializer blockと呼ばれるものもあることに注意してください。各インスタンスが作成されるときに実行されるコードの匿名ブロックです。 (構文はstaticブロックに似ていますが、staticキーワードはありません。)匿名コンストラクターには特に便利です。名前付きコンストラクターを持つことができないためです。これが実際の例です。 (予想外)GZIPOutputStreamには、圧縮レベルを指定できるコンストラクターまたはAPI呼び出しがなく、デフォルトの圧縮レベルはnoneであるため、GZIPOutputStreamをサブクラス化して圧縮を取得する必要があります。明示的なサブクラスはいつでも記述できますが、匿名クラスを記述する方が便利です。

OutputStream os = . . .;
OutputStream gzos = new GZIPOutputStream(os) {
    {
        // def is an inherited, protected field that does the actual compression
        def = new Deflator(9, true); // maximum compression, no ZLIB header
    }
};
40
Ted Hopp

クラスのインスタンスの作成中にコンストラクターが呼び出されます。

静的ブロックは、クラスローダーがこのクラス定義をロードするときに呼び出されるため、このクラスの静的メンバーを初期化できます。静的メンバーはオブジェクトではなくクラス定義の一部であるため、コンストラクターから静的メンバーを初期化しないでください。

17
ssk

クラスを初期化すると、静的イニシャライザが実行されます。これは、クラスをインスタンス化する必要はありません。ただし、コンストラクターは、クラスのインスタンスを作成するときにのみ実行されます。

例えば:

class MyClass
{   
    static
    {
        System.out.println("I am static initializer");
    }
    MyClass()
    {
        System.out.println("I am constructor");
    }

    static void staticMethod()
    {
        System.out.println("I am static method");
    }
}

実行する場合:

MyClass.staticMethod();

出力:

I am static initializer
I am static method

インスタンスを作成したことがないため、コンストラクターは呼び出されませんが、静的初期化子が呼び出されます。

クラスのインスタンスを作成すると、静的初期化子とコンストラクターの両方が実行されます。驚く様な事じゃない。

MyClass x = new MyClass();

出力:

I am static initializer
I am constructor

以下を実行する場合に注意してください。

MyClass x;

出力:(空)

変数xを宣言するには、MyClassを初期化する必要がないため、静的初期化子は実行されません。

8
Akavall

静的初期化子は、そのタイプのオブジェクトを作成しなくても、クラスがロードされるときに実行されます。

  • すべてのクラスがインスタンス化されるわけではありません。コンストラクターが呼び出されることはありません。プライベートな場合もあります。
  • コンストラクターを実行する前に、クラスの静的フィールドにアクセスしたい場合があります。
  • 静的初期化子は、クラスがロードされるときに1回だけ実行されます。コンストラクターは、インスタンス化するそのタイプのオブジェクトごとに呼び出されます。
6
Mark Byers

コンストラクターで静的変数を初期化することはできません-または少なくともおそらくshould n'tであり、特に有用ではありません。

特に、生成するために重要なロジックを必要とする静的定数を初期化しようとしている場合、それはコンストラクタではなく静的ブロックで実際に発生するはずです。

5
Louis Wasserman

静的ブロックは、コンストラクタとは異なることを行います。基本的に、2つの異なる概念があります。

静的ブロックは、クラスがメモリにロードされるときに初期化されます。これは、JVMがバイトコードを読み取ることを意味します。初期化には何でもかまいません。変数の初期化や、そのクラスのすべてのオブジェクトで共有する必要のあるその他のものを指定できます。

一方、コンストラクタはそのオブジェクトの変数のみを初期化します。

3
ved

それらは2つの別個のものです。コンストラクターを使用してクラスの1つのインスタンスを初期化します。静的初期化ブロックは、クラスがロードされるときに静的メンバーを初期化します。

3
Nathan Hughes

静的ブロックは、インスタンスがまだ作成されていない場合でも何らかのアクションを実行する必要がある場合に非常に役立ちます。例として、非静的値で静的変数を初期化する場合。

3
eppesuig

静的ブロックは、静的フィールドを初期化する場合に役立ちます。

2
Manish

静的ブロックは、インスタンスがまだ作成されていない場合でも何らかのアクションを実行する必要がある場合、コンストラクターよりも便利です。例として、非静的値で静的変数を初期化する場合。

1
Aman Kassahun

静的ブロックを理解する1つの方法は次のとおりです。コンストラクターとして機能します。ただし、2つの違いは静的ブロックはクラス変数または静的変数をインスタンス化しますが、コンストラクターはオブジェクト変数のインスタンス化に使用されます

次のクラスを検討してください

public class Part{

  String name;
  static String producer;

  public Part(String name){
      this.name = name;
  }

  static {
    producer = "Boeing";
  }

}

このクラスから作成されたオブジェクトのプロデューサーはボーイングに設定されますが、名前は渡される引数によって異なります。例えば

Part engine = new Part("JetEngine");
Part Wheel = new Part("JetWheel");
1
tadtab