it-swarm.com.de

Was ist der Unterschied zwischen einem statischen und einem nicht statischen Initialisierungscodeblock?

Meine Frage bezieht sich auf eine bestimmte Verwendung des statischen Schlüsselworts. Es ist möglich, das Schlüsselwort static zu verwenden, um einen Codeblock innerhalb einer Klasse abzudecken, die keiner Funktion angehört. Zum Beispiel kompiliert folgender Code:

public class Test {
    private static final int a;    
    static {
        a = 5;
        doSomething(a);
    }
    private static int doSomething(int x) {
        return (x+5);
    }
}

Wenn Sie das Schlüsselwort static entfernen, wird dies beanstandet, da die Variable afinal ist. Es ist jedoch möglich, die beiden Schlüsselwörter final und static zu entfernen und zu kompilieren.

Für mich ist das in beiderlei Hinsicht verwirrend. Wie soll ich einen Codeabschnitt haben, der zu keiner Methode gehört? Wie ist es möglich, es aufzurufen? Wozu dient diese Verwendung im Allgemeinen? Oder besser, wo finde ich Dokumentation dazu?

335
Szere Dyeri

Der Codeblock mit dem statischen Modifizierer kennzeichnet einen Klasse Initialisierer; Ohne den statischen Modifizierer ist der Codeblock ein Instanz Initialisierer.

Klasseninitialisierer werden in der Reihenfolge ausgeführt, in der sie definiert sind (von oben nach unten, genau wie einfache Variableninitialisierer), wenn die Klasse geladen wird (tatsächlich, wenn sie aufgelöst ist, aber das ist eine technische Frage).

Instanzinitialisierer werden in der Reihenfolge ausgeführt, in der die Klasse instanziiert wird, unmittelbar bevor der Konstruktorcode ausgeführt wird, unmittelbar nach dem Aufruf des Superkonstruktors.

Wenn Sie static aus int a Entfernen, wird es zu einer Instanzvariablen, auf die Sie über den statischen Initialisierungsblock nicht zugreifen können. Die Kompilierung mit dem Fehler "Nicht statische Variable a kann nicht aus einem statischen Kontext referenziert werden" schlägt fehl.

Wenn Sie auch static aus dem Initialisierungsblock entfernen, wird es zu einer Instanzinitialisierung und so wird int a Bei der Erstellung initialisiert.

385
Lawrence Dol

ff! Was ist statischer Initialisierer?

Der statische Initialisierer ist ein static {} Codeblock innerhalb der Klasse Java und nur einmal ausgeführt, bevor der Konstruktor oder die Hauptmethode aufgerufen wird.

OK! Erzähl mir mehr ...

  • ist ein Codeblock static { ... } innerhalb einer Java class.) und ausgeführt von einer virtuellen Maschine, wenn class aufgerufen wird.
  • Es werden keine return Anweisungen unterstützt.
  • Es werden keine Argumente unterstützt.
  • Es werden keine this oder super unterstützt.

Hmm wo kann ich es benutzen?

Kann überall dort eingesetzt werden, wo es dir gut geht :) so einfach. Aber ich sehe die meiste Zeit, wenn es verwendet wird, um Datenbankverbindung, API-Init, Protokollierung und etc. zu tun.

Nicht nur bellen! Wo ist ein Beispiel?

package com.example.learnjava;

import Java.util.ArrayList;

public class Fruit {

    static {
        System.out.println("Inside Static Initializer.");

        // fruits array
        ArrayList<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Orange");
        fruits.add("Pear");

        // print fruits
        for (String fruit : fruits) {
            System.out.println(fruit);
        }
        System.out.println("End Static Initializer.\n");
    }

    public static void main(String[] args) {
        System.out.println("Inside Main Method.");
    }
}

Ausgabe ???

Inside Static Initializer.

Apple

Orange

Birne

Static Initializer beenden.

Innerhalb der Hauptmethode.

Hoffe das hilft!

154
Madan Sapkota

Der static -Block ist ein "statischer Initialisierer".

Es wird automatisch aufgerufen, wenn die Klasse geladen wird, und es gibt keine andere Möglichkeit, sie aufzurufen (nicht einmal über Reflection).

Ich persönlich habe es nur beim Schreiben von JNI-Code verwendet:

class JNIGlue {
    static {
        System.loadLibrary("foo");
    }
}
54
Alnitak

Dies ist direkt von http://www.programcreek.com/2011/10/Java-class-instance-initializers/

1. Ausführungsreihenfolge

Schauen Sie sich die folgende Klasse an, wissen Sie, welche zuerst ausgeführt wird?

public class Foo {

    //instance variable initializer
    String s = "abc";

    //constructor
    public Foo() {
        System.out.println("constructor called");
    }

    //static initializer
    static {
        System.out.println("static initializer called");
    }

    //instance initializer
    {
        System.out.println("instance initializer called");
    }

    public static void main(String[] args) {
        new Foo();
        new Foo();
    }
}

Ausgabe:

statischer Initialisierer aufgerufen

instanzinitialisierer aufgerufen

konstruktor aufgerufen

instanzinitialisierer aufgerufen

konstruktor aufgerufen

2. Wie funktioniert der Java Instanzinitialisierer?

Der obige Instanzinitialisierer enthält eine println-Anweisung. Um zu verstehen, wie es funktioniert, können wir es als eine variable Zuweisungsanweisung behandeln, z. B. b = 0. Dies kann das Verständnis verdeutlichen.

Anstatt von

int b = 0, du könntest schreiben

int b;
b = 0;

Daher sind Instanzinitialisierer und Instanzvariableninitialisierer ziemlich gleich.

3. Wann sind Instanzinitialisierer nützlich?

Die Verwendung von Instanzinitialisierern ist selten, kann jedoch eine nützliche Alternative zu Instanzvariableninitialisierern sein, wenn:

  1. Der Initialisierungscode muss Ausnahmen behandeln
  2. Führen Sie Berechnungen durch, die mit einem Instanzvariablen-Initialisierer nicht ausgedrückt werden können.

Natürlich könnte ein solcher Code in Konstruktoren geschrieben werden. Wenn eine Klasse jedoch mehrere Konstruktoren hätte, müssten Sie den Code in jedem Konstruktor wiederholen.

Mit einem Instanzinitialisierer können Sie den Code nur einmal schreiben. Er wird ausgeführt, unabhängig davon, mit welchem ​​Konstruktor das Objekt erstellt wird. (Ich denke, dies ist nur ein Konzept und es wird nicht oft verwendet.)

Ein weiterer Fall, in dem Instanzinitialisierer nützlich sind, sind anonyme innere Klassen, die überhaupt keine Konstruktoren deklarieren können. (Ist dies ein guter Ort, um eine Protokollierungsfunktion zu platzieren?)

Danke an Derhein.

Beachten Sie auch, dass anonyme Klassen, die Interfaces [1] implementieren, keine Konstruktoren haben. Daher werden Instanzinitialisierer benötigt, um alle Arten von Ausdrücken zur Konstruktionszeit auszuführen.

37
Alexei Fando

"final" garantiert, dass eine Variable vor dem Ende des Objektinitialisierungscodes initialisiert werden muss. Ebenso garantiert "static final", dass eine Variable bis zum Ende des Klasseninitialisierungscodes initialisiert wird. Wenn Sie das "Statische" aus Ihrem Initialisierungscode weglassen, wird daraus ein Objektinitialisierungscode. somit erfüllt Ihre Variable ihre Garantien nicht mehr.

12
DJClayworth

wenn ein Entwickler einen Initialisierungsblock verwendet, kopiert der Java Compiler die Initialisierung in jeden Konstruktor der aktuellen Klasse.

Beispiel:

den folgenden Code:

class MyClass {

    private int myField = 3;
    {
        myField = myField + 2;
        //myField is worth 5 for all instance
    }

    public MyClass() {
        myField = myField * 4;
        //myField is worth 20 for all instance initialized with this construtor
    }

    public MyClass(int _myParam) {
        if (_myParam > 0) {
            myField = myField * 4;
            //myField is worth 20 for all instance initialized with this construtor
            //if _myParam is greater than 0
        } else {
            myField = myField + 5;
            //myField is worth 10 for all instance initialized with this construtor
            //if _myParam is lower than 0 or if _myParam is worth 0
        }
    }

    public void setMyField(int _myField) {
        myField = _myField;
    }


    public int getMyField() {
        return myField;
    }
}

public class MainClass{

    public static void main(String[] args) {
        MyClass myFirstInstance_ = new MyClass();
        System.out.println(myFirstInstance_.getMyField());//20
        MyClass mySecondInstance_ = new MyClass(1);
        System.out.println(mySecondInstance_.getMyField());//20
        MyClass myThirdInstance_ = new MyClass(-1);
        System.out.println(myThirdInstance_.getMyField());//10
    }
}

ist äquivalent zu:

class MyClass {

    private int myField = 3;

    public MyClass() {
        myField = myField + 2;
        myField = myField * 4;
        //myField is worth 20 for all instance initialized with this construtor
    }

    public MyClass(int _myParam) {
        myField = myField + 2;
        if (_myParam > 0) {
            myField = myField * 4;
            //myField is worth 20 for all instance initialized with this construtor
            //if _myParam is greater than 0
        } else {
            myField = myField + 5;
            //myField is worth 10 for all instance initialized with this construtor
            //if _myParam is lower than 0 or if _myParam is worth 0
        }
    }

    public void setMyField(int _myField) {
        myField = _myField;
    }


    public int getMyField() {
        return myField;
    }
}

public class MainClass{

    public static void main(String[] args) {
        MyClass myFirstInstance_ = new MyClass();
        System.out.println(myFirstInstance_.getMyField());//20
        MyClass mySecondInstance_ = new MyClass(1);
        System.out.println(mySecondInstance_.getMyField());//20
        MyClass myThirdInstance_ = new MyClass(-1);
        System.out.println(myThirdInstance_.getMyField());//10
    }
}

Ich hoffe, mein Beispiel wird von Entwicklern verstanden.

6
cardman

Sie schreiben keinen Code in einen statischen Block, der irgendwo in Ihrem Programm aufgerufen werden muss. Wenn der Zweck des Codes aufgerufen werden soll, müssen Sie ihn in eine Methode einfügen.

Sie können statische Initialisierungsblöcke schreiben, um statische Variablen zu initialisieren, wenn die Klasse geladen wird. Dieser Code kann jedoch komplexer sein.

Ein statischer Initialisierungsblock sieht aus wie eine Methode ohne Namen, ohne Argumente und ohne Rückgabetyp. Da man es nie nennt, braucht es keinen Namen. Der einzige Aufruf erfolgt, wenn die virtuelle Maschine die Klasse lädt.

6

Der statische Codeblock kann verwendet werden, um Klassenvariablen zu instanziieren oder zu initialisieren (im Gegensatz zu Objektvariablen). Wenn Sie also "a" als statisch deklarieren, bedeutet dies, dass nur eines von allen Testobjekten gemeinsam genutzt wird, und der statische Codeblock initialisiert "a" nur einmal, wenn die Testklasse zum ersten Mal geladen wird, unabhängig davon, wie viele Testobjekte erstellt werden.

4
Paul Tomblin