380 Stimmen

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, zu verwenden static Schlüsselwort, um einen Codeblock innerhalb einer Klasse abzudecken, der nicht zu einer Funktion gehört. Zum Beispiel lässt sich der folgende Code kompilieren:

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

Wenn Sie die static beschwert es sich, weil die Variable a es final . Es ist jedoch möglich, beides zu entfernen final y static und kompilieren lassen.

Das ist für mich in beiderlei Hinsicht verwirrend. Wie soll ich einen Codeabschnitt haben, der zu keiner Methode gehört? Wie ist es möglich, ihn aufzurufen? Was ist überhaupt der Zweck dieser Verwendung? Oder besser, wo kann ich eine Dokumentation dazu finden?

427voto

Lawrence Dol Punkte 61053

Der Codeblock mit dem statischen Modifikator bedeutet eine Klasse Initialisierer; ohne den statischen Modifikator ist der Codeblock ein Instanz Initialisierung.

Klasseninitialisierungen werden in der Reihenfolge ausgeführt, in der sie definiert sind (von oben nach unten, genau wie einfache Variableninitialisierungen), wenn die Klasse geladen wird (eigentlich, wenn sie aufgelöst wird, aber das ist eine Formsache).

Instanzinitialisierer werden in der Reihenfolge ausgeführt, die bei der Instanziierung der Klasse festgelegt wurde, d. h. unmittelbar vor der Ausführung des Konstruktorcodes und unmittelbar nach dem Aufruf des Superkonstruktors.

Wenn Sie die static de int a wird sie zu einer Instanzvariablen, auf die Sie über den statischen Initialisierungsblock nicht zugreifen können. Die Kompilierung schlägt mit dem Fehler "non-static variable a cannot be referenced from a static context" fehl.

Wenn Sie auch die static aus dem Initialisierungsblock, so wird er zu einem Instanzinitialisierer und damit int a wird bei der Erstellung initialisiert.

191voto

Madan Sapkota Punkte 23065

Uff! Was ist ein statischer Initialisierer?

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

OK! Erzähl mir mehr...

  • ist ein Code-Block static { ... } innerhalb einer Java-Klasse. und von der virtuellen Maschine ausgeführt, wenn die Klasse aufgerufen wird.
  • Nein return Anweisungen werden unterstützt.
  • Es werden keine Argumente unterstützt.
  • Nein this o super werden unterstützt.

Hmm, wo kann ich es verwenden?

Man kann sie überall benutzen, wo man sich wohl fühlt :) so einfach ist das. Aber ich sehe die meiste Zeit wird es verwendet, wenn die Datenbankverbindung, API-Init, Logging und etc.

Bellen Sie nicht nur! Wo ist das 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.");
    }
}

Ausgang?

Innerhalb des statischen Initialisierers.

Apfel

Orange

Birne

Ende Statischer Initialisierer.

Innerhalb der Hauptmethode.

Ich hoffe, das hilft!

62voto

Alnitak Punkte 324207

En static Block ist ein "statischer Initialisierer".

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

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

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

53voto

Alexei Fando Punkte 646

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

1. Vollstreckungsbescheid

Sehen 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();
    }
}

出力します。

statischer Initialisierer namens

Instanz-Initialisierer namens

Konstruktor genannt

Instanz-Initialisierer namens

Konstruktor genannt

2. Wie funktionieren die Java-Instanzinitialisierungen?

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

Anstelle von

int b = 0 könnten Sie schreiben

int b;
b = 0;

Daher sind Instanzinitialisierer und Instanzvariableninitialisierer so gut wie identisch.

3. Wann sind Instanzinitialisierungen sinnvoll?

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

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

Natürlich könnte ein solcher Code in Konstruktoren geschrieben werden. Aber wenn eine Klasse mehrere Konstruktoren hat, müssten Sie den Code in jedem Konstruktor wiederholen.

Mit einem Instanzinitialisierer können Sie den Code nur einmal schreiben, und er wird unabhängig davon ausgeführt, welcher Konstruktor zur Erstellung des Objekts verwendet wird. (Ich schätze, das ist nur ein Konzept, das nicht oft verwendet wird).

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

Dank an Derhein.

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

14voto

DJClayworth Punkte 25458

"final" garantiert, dass eine Variable vor dem Ende des Objektinitialisierungscodes initialisiert werden muss. Gleichermaßen garantiert "static final", dass eine Variable am Ende des Klasseninitialisierungscodes initialisiert wird. Wenn Sie das "static" aus Ihrem Initialisierungscode weglassen, wird er zu einem Objektinitialisierungscode; somit erfüllt Ihre Variable nicht mehr die Garantien.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X