it-swarm.com.de

Implementieren von Singleton mit einer Aufzählung (in Java)

Ich habe gelesen, dass es möglich ist, Singleton in Java mit einem Enum zu implementieren, wie zum Beispiel:

public enum MySingleton {
     INSTANCE;   
}

Aber wie funktioniert das oben genannte? Insbesondere muss ein Object instanziiert werden. Wie wird MySingleton hier instanziiert? Wer macht new MySingleton()?

157
Anand

Diese,

public enum MySingleton {
  INSTANCE;   
}

hat einen impliziten leeren Konstruktor. Machen Sie es stattdessen explizit,

public enum MySingleton {
    INSTANCE;
    private MySingleton() {
        System.out.println("Here");
    }
}

Wenn Sie dann eine andere Klasse mit einer main() -Methode wie hinzugefügt haben

public static void main(String[] args) {
    System.out.println(MySingleton.INSTANCE);
}

Du würdest sehen

Here
INSTANCE

enum -Felder sind Kompilierungszeitkonstanten, aber sie sind Instanzen ihres Typs enum. Und sie werden erstellt, wenn der Aufzählungstyp zum ersten Mal referenziert wird.

187
Elliott Frisch

Ein enum Typ ist ein spezieller Typ von class.

Ihr enum wird tatsächlich zu so etwas wie kompiliert

public final class MySingleton {
    public final static MySingleton INSTANCE = new MySingleton();
    private MySingleton(){} 
}

Wenn Ihr Code zum ersten Mal auf INSTANCE zugreift, wird die Klasse MySingleton von der JVM geladen und initialisiert. Dieser Prozess initialisiert das static -Feld über einmal (träge).

69

In diesem Java Best Practices Book von Joshua Bloch erfahren Sie, warum Sie die Singleton-Eigenschaft mit einem privaten Konstruktor oder einem Enum-Typ erzwingen sollten. Das Kapitel ist ziemlich lang, also fasse es zusammen:

Wenn Sie eine Klasse zu einem Singleton machen, kann es schwierig sein, ihre Clients zu testen, da es unmöglich ist, ein Singleton durch eine Scheinimplementierung zu ersetzen, es sei denn, es implementiert eine Schnittstelle, die als Typ dient. Empfohlen wird die Implementierung von Singletons, indem einfach ein Aufzählungstyp mit einem Element erstellt wird:

// Enum singleton - the preferred approach
public enum Elvis {
INSTANCE;
public void leaveTheBuilding() { ... }
}

Dieser Ansatz entspricht funktional dem Public-Field-Ansatz, ist jedoch übersichtlicher, stellt die Serialisierungs-Maschinerie kostenlos zur Verfügung und bietet eine kompromisslose Garantie gegen mehrfache Instanziierung, selbst angesichts ausgefeilter Serialisierungs- oder Reflektionsangriffe.

Obwohl dieser Ansatz noch nicht weit verbreitet ist, ist ein Einzelelement-Aufzählungstyp der beste Weg, um einen Singleton zu implementieren.

59
ekostadinov

Wie alle Enum-Instanzen instanziiert Java) jedes Objekt, wenn die Klasse geladen wird, mit der Garantie, dass es genau einmal pro JVM instanziiert wird Stellen Sie sich die INSTANCE -Deklaration als ein öffentliches statisches Endfeld vor: Java instanziiert das Objekt, wenn zum ersten Mal auf die Klasse verwiesen wird.

Die Instanzen werden während der statischen Initialisierung erstellt, die in Java Language Specification, Abschnitt 12.4 definiert ist.

Joshua Bloch beschreibt dieses Muster im Detail als Punkt 3 von Effective Java Second Edition .

9
Jeff Bowman

Da Singleton-Muster einen privaten Konstruktor hat und eine Methode zum Steuern der Instanziierungen aufruft (wie etwa getInstance), haben wir in Enums bereits einen impliziten privaten Konstruktor.

Ich weiß nicht genau, wie das JVM oder ein container die Instanzen unseres Enums steuert, aber es scheint, dass es bereits ein implizites Singleton Pattern, der Unterschied ist, dass wir kein getInstance aufrufen, sondern nur die Enumeration.

4
Bruno Franco

Wie bereits erwähnt, ist eine Enumeration eine Java -Klasse mit der besonderen Bedingung, dass ihre Definition mit mindestens einer "Enumulationskonstante" beginnen muss.

Abgesehen davon ist es eine Klasse wie jede andere und Sie verwenden sie, indem Sie Methoden unterhalb der Konstantendefinitionen hinzufügen:

public enum MySingleton {
    INSTANCE;

    public void doSomething() { ... }

    public synchronized String getSomething() { return something; }

    private String something;
}

Sie greifen auf die Methoden des Singletons folgendermaßen zu:

MySingleton.INSTANCE.doSomething();
String something = MySingleton.INSTANCE.getSomething();

Die Verwendung einer Aufzählung anstelle einer Klasse ist, wie in anderen Antworten erwähnt, hauptsächlich eine thread-sichere Instanziierung des Singleton und eine Garantie dafür, dass es sich immer nur um eine Kopie handelt.

Und vielleicht am wichtigsten ist, dass dieses Verhalten von der JVM selbst und der Java - Spezifikation garantiert wird.

Hier ist ein Abschnitt aus der Java-Spezifikation darüber, wie mehrere Instanzen einer Enum-Instanz verhindert werden:

Ein Aufzählungstyp hat keine anderen Instanzen als die durch seine Aufzählungskonstanten definierten. Es ist ein Fehler beim Kompilieren, wenn versucht wird, einen Aufzählungstyp explizit zu instanziieren. Die endgültige Klonmethode in Enum stellt sicher, dass Enum-Konstanten niemals geklont werden können, und die spezielle Behandlung durch den Serialisierungsmechanismus stellt sicher, dass infolge der Deserialisierung niemals doppelte Instanzen erstellt werden. Die reflektierte Instanziierung von Aufzählungstypen ist verboten. Zusammen stellen diese vier Dinge sicher, dass keine Instanzen eines Aufzählungstyps existieren, die über die durch die Aufzählungskonstanten definierten hinausgehen.

Bemerkenswert ist, dass nach der Instanziierung alle Thread-Sicherheitsbedenken wie in jeder anderen Klasse mit dem synchronisierten Schlüsselwort usw. behandelt werden müssen.

2
Erk