Java: Wann ist ein statischer Initialisierungsblock nützlich?

91

Was ist der Unterschied zwischen der Initialisierung innerhalb eines staticBlocks:

public class staticTest {

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

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

Und individuelle statische Initialisierung:

public class staticTest {

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

    ....
Adam Matan
quelle
1
Sie verwenden nur Zuweisungen im statischen Initialisierungsblock, daher können diese natürlich mithilfe der statischen Variablenzuweisung erfolgen. Haben Sie versucht zu sehen, was passiert, wenn Sie Anweisungen ohne Zuweisung ausführen müssen?
Platinum Azure
Es ist ein guter Ort, um Klassen oder native Bibliotheken zu laden.
Qrtt1
1
Beachten Sie, dass statische Variablen vermieden werden sollten und daher statische Initialisierungsblöcke im Allgemeinen keine gute Idee sind. Wenn Sie feststellen, dass Sie sie häufig verwenden, müssen Sie später mit Problemen rechnen.
Bill K

Antworten:

106

Ein statischer Initialisierungsblock ermöglicht eine komplexere Initialisierung, beispielsweise unter Verwendung von Bedingungen:

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

Oder wenn mehr als nur eine Konstruktion erforderlich ist: Wenn Sie zum Erstellen Ihrer Instanz einen Builder verwenden, ist eine Ausnahmebehandlung oder eine andere Arbeit als das Erstellen statischer Felder erforderlich.

Ein statischer Initialisierungsblock wird auch nach den statischen Inline-Initialisierern ausgeführt, sodass Folgendes gültig ist:

static double a;
static double b = 1;

static {
    a = b * 4; // Evaluates to 4
}
Rich O'Kelly
quelle
3
Tun "b = a * 4;" Inline wäre nur dann ein Problem, wenn b vor a deklariert würde, was in Ihrem Beispiel nicht der Fall ist.
George Hawkins
1
@GeorgeHawkins Ich habe nur versucht zu veranschaulichen, dass ein statischer Initialisierer nach Inline-Initialisierern ausgeführt wird, nicht, dass ein Äquivalent nicht inline erstellt werden kann. Ich nehme jedoch Ihren Standpunkt an und habe das Beispiel aktualisiert, um (hoffentlich) klarer zu sein.
Rich O'Kelly
1
Nur zum Spaß möchte ich darauf hinweisen, dass Ihr erstes Beispiel genauso gut "static double a = someCondition? 0: 1;" sein könnte. Nicht dass deine Beispiele nicht großartig wären, ich sage nur ... :)
Bill K
18

Eine typische Verwendung:

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

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

Wie würden Sie es ohne statischen Initialisierer tun?

gawi
quelle
2
Antwort: Guave :) +1
Paul Bellora
2
Eine weitere Antwort ohne zusätzliche Bibliotheken: Erstellen Sie eine statische Methode, die die Initialisierung von kapselt, SETund verwenden Sie den Variableninitialisierer ( private final static Set<String> SET = createValueSet()). Was wäre, wenn Sie 5 Sätze und 2 Karten hätten, würden Sie alle einfach in einen einzigen staticBlock werfen?
TWiStErRob
14

Sie können den try / catch-Block static{}wie folgt verwenden:

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: Davon verwiesen !

Karan Patel
quelle
11

Die Ausnahmebehandlung während der Initialisierung ist ein weiterer Grund. Zum Beispiel:

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

Dies ist nützlich für Konstruktoren, die wie oben ärgerlich geprüfte Ausnahmen auslösen, oder für komplexere Initialisierungslogiken, die möglicherweise zu Ausnahmen neigen.

Paul Bellora
quelle
5

Manchmal möchten Sie mehr als nur statischen Variablen Werte zuweisen. Da Sie keine beliebigen Anweisungen in den Klassenkörper einfügen können, können Sie einen statischen Initialisierungsblock verwenden.

Jesper
quelle
4

In Ihrem Beispiel gibt es keinen Unterschied. Oft ist der Anfangswert jedoch komplexer, als er bequem in einem einzelnen Ausdruck ausgedrückt werden kann (z. B. ist es List<String>ein forWert, dessen Inhalt am besten durch eine Schleife ausgedrückt wird ; oder ein Wert Method, der möglicherweise nicht vorhanden ist, sodass Ausnahmebehandlungsroutinen erforderlich sind), und / oder Die statischen Felder müssen in einer bestimmten Reihenfolge festgelegt werden.

Ruakh
quelle
4

staticBlock kann verwendet werden, um eine Singleton- Instanz zu initialisieren , um die Verwendung einer synchronisierten getInstance() Methode zu verhindern .

Donau-Seemann
quelle
3

Technisch könnte man ohne davonkommen. Einige bevorzugen mehrzeiligen Initialisierungscode für eine statische Methode. Ich bin ziemlich glücklich, einen statischen Initialisierer für eine relativ einfache Initialisierung mit mehreren Anweisungen zu verwenden.

Natürlich würde ich fast immer meine Statik machen finalund auf ein nicht veränderbares Objekt zeigen.

Tom Hawtin - Tackline
quelle
3

Das statische Schlüsselwort (ob es sich um eine Variable oder einen Block handelt) gehört zur Klasse. Wenn die Klasse aufgerufen wird, werden diese Variablen oder Blöcke ausgeführt. Daher wird der größte Teil der Initialisierung mithilfe eines statischen Schlüsselworts durchgeführt. Da es zur Klasse selbst gehört, kann die Klasse direkt darauf zugreifen, ohne eine Instanz der Klasse zu erstellen.

Nehmen wir ein Beispiel: Es gibt eine Schuhklasse, in der es verschiedene Variablen wie Farbe, Größe, Marke usw. gibt. Wenn das Schuhherstellerunternehmen nur eine Marke hat, sollten wir diese als statische Variable initialisieren. Wenn also die Schuhklasse aufgerufen wird und verschiedene Arten von Schuhen hergestellt werden (indem eine Instanz der Klasse erstellt wird), nehmen Farbe und Größe zu diesem Zeitpunkt den Speicher ein, wenn ein neuer Schuh erstellt wird. Hier ist die Marke jedoch eine gemeinsame Eigenschaft für alle Schuhe. so dass es einmal in Erinnerung bleibt, egal wie viele Schuhe hergestellt werden.

Beispiel:

    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("=================");
    }
}
imbond
quelle
1

Wir verwenden Konstruktoren, um unsere Instanzvariablen zu initialisieren (nicht statische Variablen, Variablen, die zu Objekten gehören, nicht die Klasse).

Wenn Sie Klassenvariablen (statische Variablen) initialisieren möchten und dies ohne Erstellen eines Objekts tun möchten (Konstruktoren können nur beim Erstellen eines Objekts aufgerufen werden), benötigen Sie statische Blöcke.

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);
    }
}
Michael
quelle
Das Lesen von stdin in einem statischen Initialisierer ist eine ziemlich schreckliche Idee. Und System.out.println("B * H");ist ziemlich nutzlos. Und die Antwort selbst ist ziemlich vage. OP erwähnte keine Konstruktoren oder Instanzvariablen.
Shmosel
Dies ist nur ein Beispiel, das zeigt, was ein statischer Initialisierer ist und wie er verwendet wird. OP hat nicht nach Konstruktoren oder Instanzvariablen gefragt, aber um ihm den Unterschied zwischen statischem Initialisierer und Konstruktor beizubringen, muss er das wissen. Andernfalls würde er sagen: "Warum verwende ich nicht einfach einen Konstruktor, um meine statischen Variablen zu initialisieren?"
Michael
0

Der statische Codeblock ermöglicht es, die Felder mit mehr als einer Anweisung zu initialisieren, Felder in einer anderen Reihenfolge der Deklarationen zu initialisieren und kann auch zur bedingten Intialisierung verwendet werden.

Genauer,

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

funktioniert nicht, da a und b nach ab deklariert sind.

Ich könnte jedoch einen statischen Init verwenden. Block, um dies zu überwinden.

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;
}
algolicious
quelle
3
Während das, was Sie sagen, wahr ist, zeigt es nicht die Notwendigkeit eines statischen Initialisierungsblocks. Sie können Ihre abDeklaration einfach unter die Deklaration von verschieben b.
Gawi
0

Ein statischer Initialisierungsblock ist nützlich, wenn Sie bestimmte statische Klassentypen vor der ersten Verwendung der Klasse initialisieren möchten. Bei einer späteren Verwendung werden keine statischen Initialisierungsblöcke aufgerufen. Es ist das direkte Gegenteil von Instanzinitialisierern, die Instanzmitglieder initialisieren.

Remario
quelle
0

Wenn Sie einen bestimmten Ausdruck während der Ladezeit der Klasse auswerten möchten, können Sie den statischen Block verwenden. Beachten Sie jedoch Folgendes:

Sie müssen eine Ausnahme im statischen Block behandeln, dh Sie können keine Ausnahme von einem statischen Block auslösen.

Ich bin_Pratik
quelle