Java:静的初期化ブロックはいつ役に立ちますか?


94

staticブロック内の初期化の違いは何ですか:

public class staticTest {

    static String s;
    static int n;
    static double d;

    static {
        s = "I'm static";
        n = 500;
        d = 4000.0001;
    }
    ...

そして、個々の静的初期化:

public class staticTest {

    static String s = "I'm static";
    static int n    = 500;
    static double d = 4000.0001;

    ....

1
静的初期化ブロックでのみ割り当てを使用しているため、もちろん静的変数割り当てを使用して割り当てることができます。割り当て以外のステートメントを実行する必要がある場合に何が起こるかを確認してみましたか?
プラチナアズール

クラスをロードしたり、ネイティブライブラリをロードしたりするのに適した場所です。
qrtt1 2012

1
静的変数は避ける必要があるため、静的初期化ブロックは一般的にはお勧めできません。それらを頻繁に使用していることに気付いた場合は、今後問題が発生する可能性があります。
ビルK

回答:


112

静的初期化ブロックを使用すると、たとえば条件を使用して、より複雑な初期化を行うことができます。

static double a;
static {
    if (SomeCondition) {
      a = 0;
    } else {
      a = 1;
    }
}

または、構築以上のものが必要な場合:ビルダーを使用してインスタンスを作成する場合、例外処理または静的フィールドの作成以外の作業が必要です。

静的初期化ブロックもインライン静的初期化子の後に実行されるため、以下が有効です。

static double a;
static double b = 1;

static {
    a = b * 4; // Evaluates to 4
}

3
「b = a * 4;」を実行する インラインは、bがaの前に宣言されている場合にのみ問題になりますが、この例ではそうではありません。
ジョージホーキンス

1
@GeorgeHawkins私は、静的イニシャライザーがインラインイニシャライザーの後に実行されることを説明しようとしていただけであり、同等のものをインラインで実行できないことを示していませんでした。しかし、私はあなたの主張を受け入れ、例を(うまくいけば)より明確になるように更新しました。
リッチオケリー2012

1
楽しみのために、最初の例は「static double a = someCondition?0:1;」と同じくらい簡単にできることを指摘するかもしれません。あなたの例が良くないというわけではありません、私はただ言っています... :)
ビルK

18

典型的な使用法:

private final static Set<String> SET = new HashSet<String>();

static {
    SET.add("value1");
    SET.add("value2");
    SET.add("value3");
}

静的初期化子なしでどのようにそれを行いますか?


2
回答:グアバ:) +1
Paul Bellora 2012

2
追加のライブラリを使用しない別の答え:の初期化をカプセル化する静的メソッドを作成しSET、変数initializer(private final static Set<String> SET = createValueSet())を使用します。5つのセットと2つのマップがある場合、それらすべてを1つのstaticブロックにダンプするとどうなりますか?
TWiStErRob 2016年

16

static{}以下のように、内部でtry / catchブロックを使用できます。

MyCode{

    static Scanner input = new Scanner(System.in);
    static boolean flag = true;
    static int B = input.nextInt();
    static int H = input.nextInt();

    static{
        try{
            if(B <= 0 || H <= 0){
                flag = false;
                throw new Exception("Breadth and height must be positive");
            }
        }catch(Exception e){
            System.out.println(e);
        }

    }
}

PS:これから参照されます


12

初期化中の例外処理も別の理由です。例えば:

static URL url;
static {
    try {
        url = new URL("https://blahblah.com");
    }
    catch (MalformedURLException mue) {
        //log exception or handle otherwise
    }
}

これは、上記のようにチェックされた例外を煩わしくスローするコンストラクターや、例外が発生しやすい可能性のあるより複雑な初期化ロジックに役立ちます。


5

静的変数に値を割り当てるだけでは不十分な場合があります。クラス本体に任意のステートメントを入れることはできないため、静的初期化ブロックを使用できます。


4

あなたの例では、違いはありません。ただし、多くの場合、初期値は単一の式で快適に表現されるよりも複雑です(たとえば、List<String>内容がfor-loopで最もよく表現される、またはMethod存在しない可能性があるため、例外ハンドラーが必要です)、および/または静的フィールドは特定の順序で設定する必要があります。


4

staticブロックを使用してシングルトンインスタンスを初期化し、同期 getInstance()メソッドの使用を防ぐことができます。


3

技術的には、それなしで逃げることができます。静的メソッドに入るために複数行の初期化コードを好む人もいます。比較的単純なマルチステートメントの初期化に静的初期化子を使用することは非常に満足しています。

もちろん、私はほとんどの場合、静力学finalを作成し、変更できないオブジェクトを指します。


3

静的キーワード(変数またはブロック)はクラスに属します。したがって、クラスが呼び出されると、これらの変数またはブロックが実行されます。したがって、初期化のほとんどは静的キーワードの助けを借りて行われます。クラス自体に属しているため、クラスのインスタンスを作成しなくても、クラスから直接アクセスできます。

例を見てみましょう。色、サイズ、ブランドなどのいくつかの変数がある靴のクラスがあります。ここで、靴の製造会社が1つのブランドしかない場合は、静的変数として初期化する必要があります。したがって、靴のクラスが呼び出され、さまざまな種類の靴が(クラスのインスタンスを作成することによって)製造されると、新しい靴が作成されるたびに色とサイズがメモリを占有しますが、ここではブランドはすべての靴に共通のプロパティです。靴の数に関係なく、一度だけ記憶に残るように。

例:

    class Shoe {
    int size;
    String colour;
    static String brand = "Nike";

    public Shoe(int size, String colour) {
        super();
        this.size = size;
        this.colour = colour;
    }

    void displayShoe() {
        System.out.printf("%-2d %-8s %s %n",size,colour, brand);
    }

    public static void main(String args[]) {
        Shoe s1 = new Shoe(7, "Blue");
        Shoe s2 = new Shoe(8, "White");

        System.out.println("=================");
        s1.displayShoe();
        s2.displayShoe();
        System.out.println("=================");
    }
}

1

静的コードブロックを使用すると、命令以上のフィールドを初期化し、宣言の異なる順序でフィールドを初期化でき、条件付きの初期化にも使用できます。

すなわち、

static final String ab = a+b;
static final String a = "Hello,";
static final String b = ", world";

aとbはabの後に宣言されているため、機能しません。

ただし、静的initを使用できます。これを克服するためにブロックします。

static final String ab;
static final String a;
static final String b;

static {
  b = ", world";
  a = "Hello";
  ab = a + b;
}

static final String ab;
static final String a;
static final String b;

static {
  b = (...) ? ", world" : ", universe";
  a = "Hello";
  ab = a + b;
}

3
あなたが言っていることは真実ですが、それは静的初期化ブロックの必要性を示していません。ab宣言をの宣言の下に移動するだけですb
gawi 2012

1

コンストラクターを使用して、インスタンス変数(非静的変数、クラスではなくオブジェクトに属する変数)を初期化します。

クラス変数(静的変数)を初期化し、オブジェクトを作成せずに初期化する場合(コンストラクターはオブジェクトの作成時にのみ呼び出すことができます)、静的ブロックが必要です。

static Scanner input = new Scanner(System.in);
static int widht;
static int height;

static
{
    widht = input.nextInt();
    input.nextLine();
    height = input.nextInt();
    input.close();

    if ((widht < 0) || (height < 0))
    {
        System.out.println("java.lang.Exception: Width and height must be positive");
    }
    else
    {
        System.out.println("widht * height = " + widht * height);
    }
}

静的初期化子でstdinを読み取ることは、かなりひどい考えです。そしてSystem.out.println("B * H");、かなり役に立たない。そして、答え自体はかなり曖昧です。OPはコンストラクターやインスタンス変数については言及していません。
shmosel 2018

これは、静的初期化子とは何か、およびその使用方法を示す単なる例です。OPはコンストラクターやインスタンス変数を要求しませんでしたが、静的初期化子とコンストラクターの違いを教えるためには、それを知る必要があります。そうでなければ、彼は「静的変数を初期化するためにコンストラクターを使用しないのはなぜですか?」と言うでしょう。
マイケル

0

静的初期化ブロックは、クラスを最初に使用する前に、指定されたクラスの静的型を初期化する場合に役立ちます。その後の使用では、静的初期化ブロックは呼び出されません。これは、インスタンスメンバーを初期化するインスタンス初期化子の正反対です。


0

クラスのロード中に特定の式を評価する場合は、静的ブロックを利用できますが、次の点に注意してください。

静的ブロックで例外を処理する必要があります。つまり、静的ブロックから例外をスローすることはできません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.