Frage Was ist ein Initialisierungsblock?


Wir können Code in einen Konstruktor oder eine Methode oder einen Initialisierungsblock einfügen. Was nützt der Initialisierungsblock? Ist es notwendig, dass jedes Java-Programm es haben muss?


75
2017-10-21 12:28


Ursprung


Antworten:


Vor allem gibt es zwei Arten von Initialisierungsblöcke:

  • Instanzinitialisierungsblöcke, und
  • statische Initialisierungsblöcke.

Dieser Code sollte die Verwendung von ihnen veranschaulichen und in welcher Reihenfolge sie ausgeführt werden:

public class Test {

    static int staticVariable;
    int nonStaticVariable;        

    // Static initialization block:
    // Runs once (when the class is initialized)
    static {
        System.out.println("Static initalization.");
        staticVariable = 5;
    }

    // Instance initialization block:
    // Runs each time you instantiate an object
    {
        System.out.println("Instance initialization.");
        nonStaticVariable = 7;
    }

    public Test() {
        System.out.println("Constructor.");
    }

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

Drucke:

Static initalization.
Instance initialization.
Constructor.
Instance initialization.
Constructor.

Instanz-Itialisierungsblöcke sind nützlich, wenn Sie Code ausführen möchten, unabhängig davon, welcher Konstruktor verwendet wird oder ob Sie eine Instanzinitialisierung für anonyme Klassen durchführen möchten.


143
2017-10-21 12:46



würde gern @ aioobes Antwort hinzufügen

Reihenfolge der Ausführung:

  1. statische Initialisierungsblöcke von Superklassen

  2. statische Initialisierungsblöcke der Klasse

  3. Instanzinitialisierungsblöcke von Superklassen

  4. Konstruktoren von Superklassen

  5. Instanzinitialisierungsblöcke der Klasse

  6. Konstruktor der Klasse.

Ein paar zusätzliche Punkte, die Sie beachten sollten (Punkt 1 ist die Wiederholung von @ aioobes Antwort):

  1. Der Code im statischen Initialisierungsblock wird zur Klassenladezeit ausgeführt (und ja, das bedeutet nur einmal pro Klassenladung), bevor irgendwelche Instanzen der Klasse konstruiert werden und bevor irgendwelche statischen Methoden aufgerufen werden.

  2. Der Instanzinitialisierungsblock wird tatsächlich vom Java-Compiler in jeden Konstruktor der Klasse kopiert. Also jedes Mal, wenn der Code im Instanzinitialisierungsblock ausgeführt wird genau vor dem Code im Konstruktor.


79
2018-03-14 15:36



nette Antwort von aioobe Hinzufügen von mehr Punkten

public class StaticTest extends parent {
    static {
        System.out.println("inside satic block");
    }

    StaticTest() {
        System.out.println("inside constructor of child");
    }

    {
        System.out.println("inside initialization block");
    }

    public static void main(String[] args) {
        new StaticTest();
        new StaticTest();
        System.out.println("inside main");
    }
}

class parent {
    static {
        System.out.println("inside parent Static block");
    }
    {
        System.out.println("inside parent initialisation block");
    }

    parent() {
        System.out.println("inside parent constructor");
    }
}

das gibt

inside parent Static block
inside satic block
inside parent initialisation block
inside parent constructor
inside initialization block
inside constructor of child
inside parent initialisation block
inside parent constructor
inside initialization block
inside constructor of child
inside main

Es ist so, als würde man das Offensichtliche sagen, aber es scheint ein wenig klarer zu sein.


5
2017-07-03 06:36



Der Beispielcode, der als Antwort hier genehmigt wurde, ist korrekt, aber ich stimme damit nicht überein. Es zeigt nicht, was passiert, und ich werde Ihnen ein gutes Beispiel zeigen, um zu verstehen, wie die JVM tatsächlich funktioniert:

package test;

    class A {
        A() {
            print();
        }

        void print() {
            System.out.println("A");
        }
    }

    class B extends A {
        static int staticVariable2 = 123456;
        static int staticVariable;

        static
        {
            System.out.println(staticVariable2);
            System.out.println("Static Initialization block");
            staticVariable = Math.round(3.5f);
        }

        int instanceVariable;

        {
            System.out.println("Initialization block");
            instanceVariable = Math.round(3.5f);
            staticVariable = Math.round(3.5f);
        }

        B() {
            System.out.println("Constructor");
        }

        public static void main(String[] args) {
            A a = new B();
            a.print();
            System.out.println("main");
        }

        void print() {
            System.out.println(instanceVariable);
        }

        static void somethingElse() {
            System.out.println("Static method");
        }
    }

Bevor Sie mit dem Kommentieren des Quellcodes beginnen, werde ich Ihnen eine kurze Erklärung der statischen Variablen einer Klasse geben:

Das erste ist, dass sie Klassenvariablen heißen, sie gehören zu der Klasse und nicht zu bestimmten Instanzen der Klasse. Alle Instanzen der Klasse teilen diese statische (Klassen-) Variable. Jede Variable hat einen Standardwert, abhängig vom Primitiv oder Referenztyp. Eine andere Sache ist, wenn Sie die statische Variable in einigen Mitgliedern der Klasse neu zuweisen (Initialisierungsblöcke, Konstruktoren, Methoden, Eigenschaften) und Sie den Wert der statischen Variable ändern, nicht für eine bestimmte Instanz, sondern für alle Instanzen. Um den statischen Teil abzuschließen, werde ich sagen, dass die statischen Variablen einer Klasse nicht beim erstmaligen Erstellen der Klasse erstellt werden. Sie werden bei der Definition Ihrer Klasse erstellt, sie existieren in JVM ohne die Notwendigkeit von Instanzen. Daher ist der korrekte Zugriff statischer Member von externer Klasse (Klasse, in der sie nicht definiert sind) durch Verwendung des Klassennamens gefolgt von dot und dann des statischen Members, auf den Sie zugreifen möchten (Vorlage: <CLASS_NAME>.<STATIC_VARIABLE_NAME>).

Nun schauen wir uns den obigen Code an:

Der Einstiegspunkt ist die Hauptmethode - es gibt nur drei Codezeilen. Ich möchte auf das Beispiel verweisen, das derzeit genehmigt ist. Demnach ist die erste Sache, die nach dem Drucken von "Static Initialization block" gedruckt werden muss, "Initialization block" und hier ist meine Uneinigkeit, der nicht-statische Initialisierungsblock wird nicht vor dem Konstruktor aufgerufen, er wird vor irgendwelchen Initialisierungen der Konstruktoren aufgerufen der Klasse, in der der Initialisierungsblock definiert ist. Der Konstruktor der Klasse ist das erste, was beteiligt ist, wenn Sie ein Objekt (Instanz der Klasse) erstellen. Wenn Sie dann den Konstruktor eingeben, ist der erste aufgerufene Teil entweder implizit (Standard), Superkonstruktor oder expliziter Superkonstruktor oder expliziter Aufruf zu einem anderen Konstruktor (aber irgendwann, wenn es eine Kette von überladenen Konstruktoren gibt, ruft der letzte implizit oder explizit einen Superkonstruktor auf).

Es gibt eine polymorphe Erzeugung eines Objekts, aber bevor die Klasse B und ihre Hauptmethode eingegeben wird, initialisiert die JVM alle Klassenvariablen (statische Variablen), geht dann durch die statischen Initialisierungsblöcke, wenn sie existieren und tritt dann in die Klasse B ein und beginnt mit Ausführung der Hauptmethode. Er ruft den Konstruktor der Klasse B auf und ruft dann (implizit) den Konstruktor der Klasse A auf. Mit Polymorphie wird die im Körper des Konstruktors der Klasse A aufgerufene Methode (überschriebene Methode) in Klasse B definiert Die Variable namens instanceVariable wird vor der Reinitialisierung verwendet. Nach dem Schließen des Konstruktors der Klasse B wird der Thread an den Konstruktor der Klasse B zurückgegeben, aber er geht zuerst zum nicht statischen Initialisierungsblock vor dem Ausdruck von "Konstruktor". Zum besseren Verständnis debuggen Sie mit etwas IDE, ich bevorzuge Eclipse.


3
2018-03-14 13:48



Initialisierungsblock enthält den Code, der immer ausgeführt wird, wenn eine Instanz erstellt wird. Es wird verwendet, um den gemeinsamen Teil verschiedener Konstruktoren einer Klasse zu deklarieren / initialisieren.

Die Reihenfolge der Initialisierungskonstruktoren und des Initialisierungsblocks spielt keine Rolle, der Initialisierungsblock wird immer vor dem Konstruktor ausgeführt.

Was, wenn wir einmal Code für alle Objekte einer Klasse ausführen wollen?

Wir verwenden statischen Block in Java.


1
2017-10-10 09:45



Initialisierungsblöcke werden immer dann ausgeführt, wenn die Klasse initialisiert wird und bevor Konstruktoren aufgerufen werden. Sie werden normalerweise oberhalb der Konstruktoren in geschweiften Klammern platziert. Es ist überhaupt nicht notwendig, sie in Ihre Klassen aufzunehmen.

Sie werden normalerweise zum Initialisieren von Referenzvariablen verwendet. Dies Seite gibt eine gute Erklärung


0
2017-10-21 12:39



Die Frage ist nicht ganz klar, aber hier ist eine kurze Beschreibung, wie Sie Daten in einem Objekt initialisieren können. Nehmen wir an, Sie haben eine Klasse A, die eine Liste von Objekten enthält.

1) Setze Anfangswerte in die Felddeklaration:

class A {
    private List<Object> data = new ArrayList<Object>();
}

2) Ordne Anfangswerte im Konstruktor zu:

class A {
    private List<Object> data;
    public A() {
        data = new ArrayList<Object>();
    }
}

Diese nehmen an, dass Sie "Daten" nicht als Konstruktorargument übergeben möchten.

Die Dinge werden ein wenig schwierig, wenn Sie überladene Konstruktoren mit internen Daten wie oben mischen. Erwägen:

class B {
    private List<Object> data;
    private String name;
    private String userFriendlyName;

    public B() {
        data = new ArrayList<Object>();
        name = "Default name";
        userFriendlyName = "Default user friendly name";
    }

    public B(String name) {
        data = new ArrayList<Object>();
        this.name = name;
        userFriendlyName = name;
    }

    public B(String name, String userFriendlyName) {
        data = new ArrayList<Object>();
        this.name = name;
        this.userFriendlyName = userFriendlyName;
    }
}

Beachten Sie, dass es viel wiederholten Code gibt. Sie können dies beheben, indem Konstruktoren sich gegenseitig aufrufen, oder Sie können eine private Initialisierungsmethode verwenden, die jeder Konstruktor aufruft:

class B {
    private List<Object> data;
    private String name;
    private String userFriendlyName;

    public B() {
        this("Default name", "Default user friendly name");
    }

    public B(String name) {
        this(name, name);
    }

    public B(String name, String userFriendlyName) {
        data = new ArrayList<Object>();
        this.name = name;
        this.userFriendlyName = userFriendlyName;
    }
}

oder

class B {
    private List<Object> data;
    private String name;
    private String userFriendlyName;

    public B() {
        init("Default name", "Default user friendly name");
    }

    public B(String name) {
        init(name, name);
    }

    public B(String name, String userFriendlyName) {
        init(name, userFriendlyName);
    }

    private void init(String _name, String _userFriendlyName) {
        data = new ArrayList<Object>();
        this.name = name;
        this.userFriendlyName = userFriendlyName;
    }
}

Die beiden sind (mehr oder weniger) gleichwertig.

Ich hoffe, das gibt Ihnen einige Hinweise, wie Sie Daten in Ihren Objekten initialisieren können. Ich werde nicht über statische Initialisierungsblöcke sprechen, da dies im Moment wahrscheinlich etwas fortgeschritten ist.

EDIT: Ich habe Ihre Frage als "wie initialisiere ich meine Instanz Variablen", nicht "wie funktionieren Initialisierer Blöcke" als Initialisierer Blöcke sind ein relativ fortgeschrittenes Konzept, und aus dem Ton der Frage, es scheint, Sie fragen über das einfachere Konzept. Ich könnte falsch liegen.


0
2017-10-21 12:45