it-swarm.com.de

Arbeiten mit dem statischen Konstruktor in Java

Ich habe kein vollständiges Verständnis für statische Konstruktoren in Java erhalten. Wenn es erlaubt ist, warum ist es erlaubt? In welchen Szenarien würden Sie es verwenden? Welchen Zweck würde es erfüllen? Kann mir bitte jemand ein einfaches Beispiel geben?

11
Kapeel45

Genau genommen hat Java keine statischen Konstruktoren, da ein Konstruktor per Definition nicht statisch sein kann. Was Sie sind Das Verweisen auf wird als "statischer Initialisierungsblock" bezeichnet. Ein Konstruktor impliziert, dass Sie ein Objekt konstruieren. Sie können keinen Konstruktor für eine Klasse haben, da eine Klasse keine Instanz von sich selbst ist. Es ist einfach eine Klasse. Das, was "konstruiert". Die Klasse heißt Compiler (oder virtuelle Maschine, je nachdem, was unter "Konstrukten" zu verstehen ist). Wenn Sie Code in einem anderen Code erstellen, beginnen Sie mit der Codegenerierung, was eine ganz andere Sache ist.

Abgesehen von der Nichtauswahl wird ein statischer Initialisierungsblock verwendet, um komplexe statische Felder (oder Felder auf Klassenebene) für eine Klasse zu initialisieren. Normalerweise werden diese verwendet, um Dinge zu initialisieren, die entweder nicht in einer Zeile initialisiert werden können oder die erfordern, dass zuerst ein anderes Objekt (das möglicherweise in der Klasse ist, in der der statische Block implementiert ist oder nicht) initialisiert wird.

Grundsätzlich könnte man sie verwenden, um der Klasse zu sagen: "Hey, setze die Variable A ZUERST auf diesen Wert und verwende dann, sobald dies erledigt ist, den Wert von A, um B zu initialisieren." Da Java erfordert, dass die Standardfeldinitialisierung entweder innerhalb eines Konstruktors oder einer Methode oder über den Aufruf eines Konstruktors oder einer Methode (sofern es sich nicht um ein Literal handelt) erfolgt, können diese eine bequeme Methode zum Initialisieren sein komplexe, statische Objekte.

Statische Initialisierungsblöcke werden nicht allzu oft benötigt und sollten im Allgemeinen vermieden werden, es sei denn, sie haben eine reale Verwendung. Versteh mich nicht falsch, sie haben ihren Platz in Java, aber wie viele andere Dinge (wie break-, return-, switch- und goto-Anweisungen) können sie leicht überbeansprucht werden, was ihre Lesbarkeit und Wartbarkeit des Codes verringert -Basis, in der sie verwendet werden.

Ein kurzes Beispiel für die Verwendung eines statischen Initialisierungsblocks wäre die folgende (gemäß ausgezeichnete Erklärung der gefundenen statischen Initialisierungsblöcke hier =):

Code:

public class StaticExample{
    static {
        System.out.println("This is first static block");
    }

    public StaticExample(){
        System.out.println("This is constructor");
    }

    public static String staticString = "Static Variable";

    static {
        System.out.println("This is second static block and "
                                                    + staticString);
    }

    public static void main(String[] args){
        StaticExample statEx = new StaticExample();
        StaticExample.staticMethod2();
    }

    static {
        staticMethod();
        System.out.println("This is third static block");
    }

    public static void staticMethod() {
        System.out.println("This is static method");
    }

    public static void staticMethod2() {
        System.out.println("This is static method2");
    }
}    

Ausgabe:

This is first static block
This is second static block and Static Variable
This is static method
This is third static block
This is constructor
This is static method2

Einige Fälle, in denen statische Blöcke nützlich sein können:

  • Wenn Sie Treiber und andere Elemente in den Namespace laden. Zum Beispiel hat die Klassenklasse einen statischen Block, in dem sie die Eingeborenen registriert.
  • Wenn Sie eine Berechnung durchführen müssen, um Ihre statischen Variablen zu initialisieren, können Sie einen statischen Block deklarieren, der beim ersten Laden der Klasse genau einmal ausgeführt wird.
  • Sicherheitsprobleme oder Protokollierungsaufgaben

Einige Gründe, statische Blöcke NICHT zu verwenden (in anderen Situationen):

  • Es gibt eine Einschränkung von JVM, dass ein statischer Initialisierungsblock 64 KB nicht überschreiten darf.
  • Sie können keine geprüften Ausnahmen auslösen.
  • Sie können das Schlüsselwort this nicht verwenden, da keine Instanz vorhanden ist.
  • Sie sollten nicht versuchen, auf Super zuzugreifen, da es für statische Blöcke keine solche Funktion gibt.
  • Sie sollten nichts von diesem Block zurückgeben.
  • Statische Blöcke machen das Testen zu einem Albtraum.

Ich sollte beachten: Während einige Sprachen (wie C #) möglicherweise eine Syntax für "Konstruktoren" haben, die statisch sind, funktionieren diese "Konstruktoren" ähnlich wie statische Initialisierungsblöcke in Java und werden von vielen (ich selbst eingeschlossen) als angesehen Fehlbezeichnungen in der Sprache angesichts des Grundkonzepts eines OOP-Konstruktors .

28
Gurgadurgen

es wird verwendet, um Felder zu initialisieren, die schwieriger sind, als sie einfach zuzuweisen:

public class Example{

    public final static Map<String, String> preFilledField;

    static{
        Map<String, String> tmp = new HashMap<>();
        //fill map
        preFilledField = Collections.unmodifiableMap(tmp);
    }
}

es ist nicht möglich, eine Karte bei der Initialisierung zu füllen (es sei denn, Sie verwenden den anonymen Unterklassen-Hack). Dies ist daher der beste Weg, um sicherzustellen, dass sie vor der ersten Verwendung gefüllt wird

Sie können dies auch tun, um beim Initialisieren aktivierte Ausnahmen abzufangen

5
ratchet freak

Gurgadurgens Antwort ist wahrscheinlich das, wonach Sie suchen, aber ich füge nur ein paar andere Punkte hinzu, die manchmal vernachlässigt werden, wenn jemand einen "statischen Konstruktor" will.

Wenn Sie eine statische Methode wünschen, die eine Instanz Ihrer Klasse erstellt, können Sie eine statische Methode erstellen, die einfach den Konstruktor der Klasse aufruft.

public class Example
{
    /** Static method to create an instance. */
    public static Example build()
    { return new Example() ; }

    /** A field of each instance. */
    private String stuff ;

    /** The class's actual constructor. */
    public Example()
    { stuff = new String() ; }

    public String getStuff()
    { return this.stuff ; }

    /**
     * Mutator for "stuff" property. By convention this returns "void"
     * but you might want to return the object itself, to support the
     * sort of chained invocations that are becoming trendy now. You'll
     * see the stylistic benefits of chaining later in this example.
     */
    public Example setStuff( String newStuff )
    {
        this.stuff = newStuff ;
        return this ;
    }
}

public class ExampleTest
{
    public static void main( String[] args )
    {
        // The usual instance model.
        Example first = new Example() ;
        System.out.println( first.setStuff("stuff").getStuff() ) ;

        // Using your static method to construct an instance:
        Example second = Example.build() ;
        System.out.println( second.setStuff("more stuff").getStuff() ) ;

        // Chaining all the invocations at once:
        System.out.println( Example.build().setStuff("even more stuff").getStuff() ) ;
    }
}

Dies erzeugt die Ausgabe:

stuff
more stuff
even more stuff

Der andere Grund, eine statische Methode zum Erstellen einer Instanz zu erstellen, ist der Fall, wenn Sie sicherstellen möchten, dass genau eine Instanz Ihrer Klasse zu einem bestimmten Zeitpunkt vorhanden ist ;; Dies wird als Singleton bezeichnet. Konventionell würde eine solche Klasse eine statische Methode namens getInstance() bereitstellen, um die einzige Instanz zu erhalten, die als "behandelt wird. Singleton ".

public class SingletonExample extends Example
{
    // Note: This extends my previous example, which has a "stuff"
    // property, and a trivial constructor.

    /** The singleton instance, statically initialized as null. */
    private static SingletonExample singleton = null ;

    /**
     * The static accessor for the singleton. If no instance exists,
     * then it will be created; otherwise, the one that already exists
     * will be returned.
     */
    public static SingletonExample getInstance()
    {
        if( singleton == null )
            singleton = new SingletonExample() ;
        return singleton ;
    }
}

public class SingletonExampleTest
{
    public static void main( String[] args )
    {
        System.out.println( SingletonExample.getInstance().setStuff("stuff").getStuff() ) ;

        // You could still create instances of this class normally if you want to.
        SingletonExample otherstuff = new SingletonExample() ;
        otherstuff.setStuff("other stuff") ;

        // But watch what happens to this.
        System.out.println( SingletonExample.getInstance().getStuff() ) ;
        System.out.println( otherstuff.getStuff() ) ;

        // Now we show what happens when you start modifying the singleton.
        SingletonExample theoneandonly = SingletonExample.getInstance() ;
        theoneandonly.setStuff("changed stuff") ;
        System.out.println( SingletonExample.getInstance().getStuff() ) ;
    }
}

Dies erzeugt Folgendes.

stuff
stuff
other stuff
changed stuff

Durch Speichern eines Verweises auf den Singleton und anschließendes Ändern erhält der nächste Aufruf von getInstance() diesen geänderten Singleton.

Es ist verlockend, Singletons zu verwenden, um globale Variablen für Ihre Anwendung zu erstellen. In einigen Kontexten kann dies nützlich sein, aber es kann Sie auch in Schwierigkeiten bringen. Insbesondere beim Entwickeln einer Android App), bei der Singleton-Instanzen verloren gehen könnten, stieß ich auf einen interessanten Fehler. Das Springen von einer Aktivität zur nächsten kann manchmal dazu führen, dass die JVM einen neuen "Klassenlader" verwendet, der Ich weiß nichts über den Singleton, der von einem früheren Klassenladeprogramm statisch gespeichert wurde.

2
zerobandwidth

Obwohl ich verstehe, dass es viele gibt, die den Begriff eines "statischen Konstruktors" als Fehlbezeichnung ansehen, glaube ich nicht, dass dies der Fall ist. Das Problem besteht darin, beide Klassen und ihre Instanzobjekte zu erstellen. In anderen Threads wurde angegeben, dass die Konstruktion der Klasse die Aufgabe des Compilers ist. Selbst in Java ist dies nur zur Hälfte der Fall.

Der Compiler erstellt für jede Klassendefinition ein Gerüst. Das Gerüst enthält Metadaten über die Klasse und welche Instanzen zum Zeitpunkt der Erstellung enthalten sein sollten. Wenn eine Klasse ein Feld definiert, dem ein konstanter Grundwert zugewiesen ist, wird dieser Wert vom Compiler in das Gerüst aufgenommen. Für alle anderen zugewiesenen Werttypen generiert der Compiler eine Initialisierungsroutine, die vor der Erstellung der Instanz der ersten Klasse einmal ausgeführt werden soll und das Gerüst mit den richtigen Werten aktualisiert. Dieses Update kann vom Compiler nicht durchgeführt werden.

Da diese einmalige Aktualisierung des Gerüsts häufig eine wichtige Voraussetzung für das ordnungsgemäße Funktionieren der Instanzkonstruktoren ist, ist es auch sinnvoll, sie als Konstruktortyp zu bezeichnen. Aus diesem Grund wird es in gemeinsamen OO - Sprachen, die das Konzept unterstützen, als statischer Konstruktor bezeichnet. Das Konzept hinter den statischen Initialisierungsblöcken in Java ist kaum mehr als Eine semantische Änderung, um mit der Vorstellung Schritt zu halten, dass ein Java Programmierer sowohl system- als auch implementierungsunabhängig sein sollte.

0
Arkain

Wie andere Antworten bereits sagten, können Sie statische Methoden schreiben, die ein Objekt erstellen. Dies umgeht das Fehlen benannter Konstruktoren in Java (und vielen anderen Sprachen. Delphi unterstützt benannte Konstruktoren). Sie können mit den Typen und der Reihenfolge der Parameter spielen, dies kann jedoch zu Unklarheiten und Fragilität führen Code.

Zum Beispiel könnten wir ein Szenario erfinden, in dem Ihr Objekt aus einer XML-Zeichenfolge oder einer JSON-Zeichenfolge erstellt werden kann. Sie könnten Methoden schreiben wie:

static MyObject createFromXml(String xml);
static MyObject createFromJson(String json);

Ich habe dies sehr gelegentlich als Alternative zu einem parameterlosen Konstruktor mit benannten Initialisierungsmethoden verwendet:

MyObject myObject = new MyObject();
myObject.loadXml(xml). 

Sie können eine statische Erstellungsmethode als Implementierung des Builder-Musters in Ihrer Klasse betrachten.

0
kiwiron