Quel est l’avantage d’un enum Java par rapport à une classe avec des champs finaux statiques publics?

Je connais très bien C # mais commence à travailler davantage en Java. Je m’attendais à apprendre que les énumérations en Java étaient fondamentalement équivalentes à celles en C # mais apparemment ce n’est pas le cas. Au début, j’étais enthousiasmé d’apprendre que les énumérations Java pouvaient contenir plusieurs éléments de données, ce qui semble très avantageux ( http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html ). Cependant, depuis lors, j’ai trouvé de nombreuses fonctionnalités qui sont sortingviales en C #, telles que la possibilité d’atsortingbuer une valeur à un élément enum et, par conséquent, la possibilité de convertir un nombre entier en un effort sans effort décent ( C’est-à-dire convertir la valeur entière en Java Enum correspondant .

Donc, ma question est la suivante: yat-il des avantages pour Java enum sur une classe avec un tas de champs finaux statiques publics? Ou fournit-il simplement une syntaxe plus compacte?

EDIT: Permettez-moi d’être plus clair. Quel est l’avantage de Java enums sur une classe avec un tas de champs finaux statiques publics du même type ? Par exemple, dans l’exemple des planètes du premier lien, quel est l’avantage d’un enum sur une classe avec ces constantes publiques:

public static final Planet MERCURY = new Planet(3.303e+23, 2.4397e6); public static final Planet VENUS = new Planet(4.869e+24, 6.0518e6); public static final Planet EARTH = new Planet(5.976e+24, 6.37814e6); public static final Planet MARS = new Planet(6.421e+23, 3.3972e6); public static final Planet JUPITER = new Planet(1.9e+27, 7.1492e7); public static final Planet SATURN = new Planet(5.688e+26, 6.0268e7); public static final Planet URANUS = new Planet(8.686e+25, 2.5559e7); public static final Planet NEPTUNE = new Planet(1.024e+26, 2.4746e7); 

Pour autant que je sache, la réponse de casablanca est la seule qui le satisfasse.

Techniquement, on pourrait en effet considérer les enums comme une classe avec un ensemble de constantes typées, et c’est en fait la manière dont les constantes enum sont implémentées en interne. L’utilisation d’un enum vous donne cependant des méthodes utiles ( Enum javadoc ) que vous devriez implémenter vous-même, comme Enum.valueOf .

  1. Tapez sécurité et valeur sécurité.
  2. Singleton garanti.
  3. Possibilité de définir et de remplacer les méthodes.
  4. Possibilité d’utiliser des valeurs dans les déclarations de case instruction switch sans qualification.
  5. Séquentialisation intégrée des valeurs via ordinal().
  6. Sérialisation par nom et non par valeur, ce qui offre un certain degré de pérennité.
  7. EnumSet et EnumMap .

Personne n’a mentionné la possibilité de les utiliser dans des instructions de switch . Je vais aussi le dire.

Cela permet d’utiliser des énumérations complexes arbitrairement sans utiliser instanceof , les séquences potentiellement confuses, ou les valeurs de commutation non-ssortingng / int. L’exemple canonique est une machine à états.

Il y a moins de confusion. Prenez la Font par exemple. Il a un constructeur qui prend le nom de la Font vous voulez, sa taille et son style ( new Font(Ssortingng, int, int) ). À ce jour, je ne me souviens plus si le style ou la taille passe en premier. Si Font avait utilisé une enum pour tous ses différents styles ( PLAIN , BOLD , ITALIC , BOLD_ITALIC ), son constructeur ressemblerait à Font(Ssortingng, Style, int) , évitant toute confusion. Malheureusement, les enum s n’étaient pas présents lors de la création de la classe Font , et comme Java doit maintenir une compatibilité inverse, nous serons toujours en proie à cette ambiguïté.

Bien sûr, il ne s’agit que d’un argument pour utiliser une enum au lieu des constantes public static final . Enums sont également parfaits pour les singletons et implémenter le comportement par défaut tout en permettant une personnalisation ultérieure (IE le modèle de stratégie ). Un exemple de ces derniers est OpenOption et StandardOpenOption java.nio.file : si un développeur voulait créer son propre OpenOption non standard, il pourrait le faire.

Le principal avantage est la sécurité de type. Avec un ensemble de constantes, toute valeur du même type insortingnsèque pourrait être utilisée, introduisant des erreurs. Avec un enum, seules les valeurs applicables peuvent être utilisées.

Par exemple

 public static final int SIZE_SMALL = 1; public static final int SIZE_MEDIUM = 2; public static final int SIZE_LARGE = 3; public void setSize(int newSize) { ... } obj.setSize(15); // Comstacks but likely to fail later 

contre

 public enum Size { SMALL, MEDIUM, LARGE }; public void setSize(Size s) { ... } obj.setSize( ? ); // Can't even express the above example with an enum 

Il y a beaucoup de bonnes réponses ici, mais aucune ne mentionne qu’il existe des implémentations hautement optimisées des classes / interfaces d’API Collection spécifiquement pour les énumérations :

  • EnumSet
  • EnumMap

Ces classes spécifiques à enum n’acceptent que les instances Enum (les EnumMap acceptent uniquement les Enum uniquement comme clés) et, dans la mesure du possible, elles reviennent à la représentation compacte et à la manipulation des bits dans leur implémentation.

Qu’est-ce que ça veut dire?

Si notre type Enum ne contient pas plus de 64 éléments (la plupart des exemples Enum réels seront qualifiés pour cela), les implémentations stockent les éléments dans une seule valeur long , chaque instance Enum en question sera associée à un peu de cette 64- peu long long . Ajouter un élément à un EnumSet c’est simplement mettre le bon bit à 1, le supprimer ne fait que mettre ce bit à 0. Tester si un élément est dans le Set n’est qu’un test bitmask! Maintenant, tu dois aimer Enum s pour ça!

Le premier avantage des énumérations, comme vous l’avez déjà remarqué, est la simplicité de la syntaxe. Mais le point essentiel de l’énumération est de fournir un ensemble de constantes bien connues qui, par défaut, forment une plage et permettent d’effectuer une parsing de code plus complète grâce à des contrôles de sécurité de type et de valeur.

Ces atsortingbuts de énumérations aident à la fois un programmeur et un compilateur. Par exemple, supposons que vous voyez une fonction qui accepte un entier. Qu’est-ce que ce nombre entier pourrait signifier? Quel genre de valeurs pouvez-vous transmettre? Vous ne savez pas vraiment tout de suite. Mais si vous voyez une fonction qui accepte l’énumération, vous connaissez très bien toutes les valeurs possibles que vous pouvez transmettre.

Pour le compilateur, enums aide à déterminer une plage de valeurs et à moins que vous n’affectiez des valeurs spéciales aux membres enum, elles sont bien comsockets entre 0 et plus. Cela permet de détecter automatiquement les erreurs dans le code grâce à des contrôles de sécurité de type, etc. Par exemple, le compilateur peut vous avertir que vous ne gérez pas toutes les valeurs d’énumération possibles dans votre instruction switch (c’est-à-dire lorsque vous n’avez pas de cas default et que vous ne gérez qu’une seule des valeurs enum). Il vous avertit également lorsque vous convertissez un nombre entier arbitraire en enum, car la plage de valeurs d’énum est inférieure à celle d’un nombre entier et peut à son tour déclencher des erreurs dans la fonction qui n’accepte pas un entier. De plus, la création d’une table de saut pour le commutateur devient plus facile lorsque les valeurs sont comsockets entre 0 et plus.

Ceci n’est pas seulement vrai pour Java, mais également pour d’autres langages avec une vérification de type ssortingcte. C, C ++, D, C # sont de bons exemples.

Exemple:

 public class CurrencyDenom { public static final int PENNY = 1; public static final int NICKLE = 5; public static final int DIME = 10; public static final int QUARTER = 25;} 

Limitation des constantes Java

1) Non Type-Safety : Tout d’abord, il n’est pas sûr de type; vous pouvez affecter n’importe quelle valeur int à int, par exemple 99, bien qu’il n’y ait pas de pièce pour représenter cette valeur.

2) Aucune impression significative : la valeur d’impression de n’importe laquelle de ces constantes imprimera sa valeur numérique au lieu du nom significatif de la pièce, par exemple lorsque vous imprimez NICKLE, il affichera “5” au lieu de “NICKLE”

3) Pas d’espace de nommage : pour accéder à la constante currencyDenom, il est nécessaire de préfixer le nom de la classe, par exemple CurrencyDenom.PENNY, au lieu d’utiliser simplement PENNY, mais cela peut également être réalisé en utilisant l’importation statique dans JDK 1.5.

Avantage de enum

1) Enums en Java sont de type sécurisé et ont leur propre espace de nom. Cela signifie que votre énumération aura un type par exemple “Devise” dans l’exemple ci-dessous et que vous ne pouvez pas affecter de valeur autre que celle spécifiée dans les constantes Enum.

 public enum Currency {PENNY, NICKLE, DIME, QUARTER}; 

Currency coin = Currency.PENNY; coin = 1; //compilation error

2) Enum en Java est un type de référence comme classe ou interface et vous pouvez définir des constructeurs, des méthodes et des variables à l’intérieur de java Enum, ce qui le rend plus puissant que Enum en C et C ++.

3) Vous pouvez spécifier des valeurs de constantes enum au moment de la création, comme indiqué dans l’exemple ci-dessous: Devise publique enum {PENNY (1), NICKLE (5), DIME (10), QUARTER (25)}; Mais pour que cela fonctionne, vous devez définir une variable membre et un constructeur car PENNY (1) appelle en réalité un constructeur qui accepte int value, voir ci-dessous exemple.

 public enum Currency { PENNY(1), NICKLE(5), DIME(10), QUARTER(25); private int value; private Currency(int value) { this.value = value; } 

};

Fréquence: http://javarevisited.blogspot.in/2011/08/enum-in-java-example-tutorial.html

Enum Avantages:

  1. Les énumérations sont sûres, les champs statiques ne sont pas
  2. Il y a un nombre fini de valeurs (il n’est pas possible de passer une valeur enum non existante. Si vous avez des champs de classe statiques, vous pouvez faire cette erreur)
  3. Chaque enum peut avoir plusieurs propriétés (champs / getters) assignées – encapsulation. Aussi quelques méthodes simples: YEAR.toSeconds () ou similaire. Compare: Colors.RED.getHex () avec Colors.toHex (Colors.RED)

“comme la possibilité d’atsortingbuer facilement une valeur à un élément enum”

 enum EnumX{ VAL_1(1), VAL_200(200); public final int certainValue; private X(int certainValue){this.certainValue = certainValue;} } 

“et par conséquent la possibilité de convertir un nombre entier en enum sans effort décent” Ajouter une méthode convertissant int en enum qui le fait. Ajoutez simplement le HashMap statique contenant le mappage.

Si vous voulez vraiment convertir ord = VAL_200.ordinal () en val_200, utilisez juste: EnumX.values ​​() [ord]

Un enum est implicitement final, avec un constructeur privé, toutes ses valeurs sont du même type ou un sous-type, vous pouvez obtenir toutes ses valeurs en utilisant values() , obtenir sa valeur name() ou ordinal() ou vous pouvez regarder un enum par numéro ou nom.

Vous pouvez également définir des sous-classes (même si théoriquement final, quelque chose que vous ne pouvez pas faire autrement)

 enum Runner implements Runnable { HI { public void run() { System.out.println("Hello"); } }, BYE { public void run() { System.out.println("Sayonara"); } public Ssortingng toSsortingng() { return "good-bye"; } } } class MYRunner extends Runner // won't comstack. 

Une autre différence importante est que le compilateur Java traite static final champs static final des types primitifs et des chaînes comme des littéraux. Cela signifie que ces constantes deviennent en ligne. C’est similaire au préprocesseur C/C++ #define . voir cette question SO. Ce n’est pas le cas avec les énumérations.

Vous obtenez la vérification de la compilation des valeurs valides lorsque vous utilisez un enum. Regardez cette question.

Le plus grand avantage est enum Singletons sont faciles à écrire et à thread-safe:

 public enum EasySingleton{ INSTANCE; } 

et

 /** * Singleton pattern example with Double checked Locking */ public class DoubleCheckedLockingSingleton{ private volatile DoubleCheckedLockingSingleton INSTANCE; private DoubleCheckedLockingSingleton(){} public DoubleCheckedLockingSingleton getInstance(){ if(INSTANCE == null){ synchronized(DoubleCheckedLockingSingleton.class){ //double checking Singleton instance if(INSTANCE == null){ INSTANCE = new DoubleCheckedLockingSingleton(); } } } return INSTANCE; } } 

les deux sont similaires et il a géré la sérialisation par eux-mêmes en mettant en œuvre

 //readResolve to prevent another instance of Singleton private Object readResolve(){ return INSTANCE; } 

plus

Je pense qu’un enum ne peut être final , car sous le capot, le compilateur génère des sous-classes pour chaque entrée d’ enum .

Plus d’informations De la source

C’est généralement considéré comme une mauvaise pratique. Le problème est que les constantes font partie de l’interface publique (à défaut d’un meilleur mot) de la classe d’implémentation. Cela signifie que la classe d’implémentation publie toutes ces valeurs dans des classes externes même si elles ne sont requirejses qu’en interne. Les constantes prolifèrent dans tout le code. Un exemple est l’interface SwingConstants dans Swing, qui est implémentée par des dizaines de classes qui “réexportent” toutes leurs constantes (même celles qu’elles n’utilisent pas) comme étant les leurs.
Le modèle d’interface constant est une mauvaise utilisation des interfaces. Le fait qu’une classe utilise des constantes en interne est un détail d’implémentation. L’implémentation d’une interface constante entraîne la fuite de ce détail d’implémentation dans l’API exscope de la classe. Les utilisateurs d’une classe n’ont aucune conséquence sur le fait que la classe implémente une interface constante. En fait, cela peut même les confondre. Pire encore, cela représente un engagement: si, dans une prochaine version, la classe est modifiée pour ne plus avoir à utiliser les constantes, elle doit toujours implémenter l’interface pour garantir la compatibilité binary. Si une classe non finale implémente une interface constante, toutes les sous-classes auront leurs espaces de noms pollués par les constantes de l’interface.
Un enum peut être une meilleure approche. Ou vous pourriez simplement mettre les constantes en tant que champs statiques publics dans une classe qui ne peut pas être instanciée. Cela permet à une autre classe d’y accéder sans polluer sa propre API.