Implémentation de Singleton avec un Enum (en Java)

J’ai lu qu’il est possible d’implémenter Singleton en Java en utilisant un Enum tel que:

 public enum MySingleton { INSTANCE; } 

Mais comment cela fonctionne-t-il? Plus précisément, un Object doit être instancié. Comment MySingleton est-il instancié? Qui fait le new MySingleton() ?

Ce,

 public enum MySingleton { INSTANCE; } 

a un constructeur implicite vide. Soyons explicites à la place,

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

Si vous avez ensuite ajouté une autre classe avec une méthode main() comme

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

Tu verrais

 Here INSTANCE 

enum champs enum sont des constantes de temps de compilation, mais ce sont des instances de leur type enum . Et, ils sont construits lorsque le type enum est référencé pour la première fois.

Dans ce livre sur les meilleures pratiques Java de Joshua Bloch, vous pouvez découvrir pourquoi vous devez appliquer la propriété Singleton à un constructeur privé ou à un type Enum. Le chapitre est assez long, alors gardez le résumé:

Faire une classe un Singleton peut compliquer le test de ses clients, car il est impossible de remplacer une implémentation fictive par un singleton, sauf si elle implémente une interface qui lui sert de type. L’approche recommandée est d’implémenter Singletons en créant simplement un type enum avec un élément:

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

Cette approche est fonctionnellement équivalente à l’approche du domaine public, sauf qu’elle est plus concise, fournit la machinerie de sérialisation gratuitement et offre une garantie absolue contre l’instanciation multiple, même en cas d’attaques sophistiquées de sérialisation ou de reflection.

Bien que cette approche n’ait pas encore été largement adoptée, un type enum à un seul élément est le meilleur moyen d’implémenter un singleton.

Un type enum est un type spécial de type de class .

Votre déclaration enum comstack en fait quelque chose comme

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

Lorsque votre code accède pour la première fois à INSTANCE , la classe MySingleton sera chargée et initialisée par la JVM. Ce processus initialise le champ static ci-dessus une fois (paresseusement).

Comme toutes les instances d’énumération, Java instancie chaque object lorsque la classe est chargée, avec la garantie qu’il est instancié exactement une fois par JVM . Considérez la déclaration INSTANCE comme un champ final statique public: Java instanciera l’object lors de la première référence à la classe.

Les instances sont créées lors de l’initialisation statique, définie à la section 12.4 de la spécification du langage Java .

Pour ce que cela vaut, Joshua Bloch décrit ce modèle en détail sous le point 3 de Effective Java Second Edition .

Comme Singleton Pattern consiste à avoir un constructeur privé et à appeler une méthode pour contrôler les instanciations (comme certaines getInstance ), dans Enums nous avons déjà un constructeur privé implicite.

Je ne sais pas exactement comment la JVM ou un conteneur contrôle les instances de nos Enums , mais il semble qu’il utilise déjà un Singleton Pattern implicite, la différence étant que nous getInstance pas getInstance , nous appelons simplement Enum.

Comme cela a été mentionné, dans une certaine mesure, une énumération est une classe Java avec la condition spéciale que sa définition doit commencer par au moins une “constante enum”.

En partie, c’est une classe comme n’importe quelle classe et vous l’utilisez en ajoutant des méthodes en dessous des définitions constantes:

 public enum MySingleton { INSTANCE; public void doSomething() { ... } public synchronized Ssortingng getSomething() { return something; } private Ssortingng something; } 

Vous accédez aux méthodes du singleton selon ces lignes:

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

L’utilisation d’une enum, au lieu d’une classe, est, comme cela a été mentionné dans d’autres réponses, principalement au sujet d’une instanciation du singleton et d’une garantie qu’il ne s’agira que d’une copie.

Et, plus important peut-être, ce comportement est garanti par la JVM elle-même et la spécification Java.

Voici une section de la spécification Java sur la manière dont plusieurs instances d’une instance enum sont empêchées:

Un type enum n’a aucune instance autre que celles définies par ses constantes enum. C’est une erreur de compilation pour tenter d’instancier explicitement un type enum. La méthode de clonage finale dans Enum garantit que les constantes enum ne peuvent jamais être clonées, et le traitement spécial par le mécanisme de sérialisation garantit que les instances en double ne sont jamais créées suite à la désérialisation. L’instanciation réfléchie des types enum est interdite. Ensemble, ces quatre éléments garantissent qu’aucune instance de type enum n’existe au-delà de celles définies par les constantes enum.

Il convient de noter que, après l’instanciation, toute préoccupation relative à la sécurité des threads doit être traitée comme dans toute autre classe avec le mot-clé synchronisé, etc.