Quelles sont les différences entre un Java enum et une classe avec un constructeur privé? [dupliquer]
cette question a déjà une réponse ici:
- Quel est l'avantage D'un Java enum par rapport à une classe avec des champs finaux publics statiques? 15 réponses
j'ai essayé de comprendre comment Java enum fonctionne vraiment et j'en suis venu à la conclusion qu'il est très similaire à un normal Classe Java dont le constructeur est déclaré privé.
je viens juste d'arriver à cette conclusion et elle n'est pas basée sur beaucoup de réflexion, mais J'aime savoir si je manque quelque chose.
donc ci-dessous est une implémentation D'un simple Java enum et d'une classe Java équivalente.
public enum Direction {
ENUM_UP(0, -1),
ENUM_DOWN(0, 1),
ENUM_RIGHT(1, 0),
ENUM_LEFT(-1, 0);
private int x;
private int y;
private Direction(int x, int y){
this.x = x;
this.y = y;
}
public int getEnumX(){
return x;
}
public int getEnumY(){
return y;
}
}
Quelle est la différence de signification entre le code ci-dessus et celui ci-dessous?
public class Direction{
public static final Direction UP = new Direction(0, -1) ;
public static final Direction DOWN = new Direction(0, 1) ;
public static final Direction LEFT = new Direction(-1, 0) ;
public static final Direction RIGHT = new Direction(1, 0) ;
private int x ;
private int y ;
private Direction(int x, int y){
this.x = x ;
this.y = y ;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
}
5 réponses
Différences:
- Enums étendre
java.lang.Enum
et de gagner tout son nice features :- Automatique singleton comportement grâce à un bon de sérialisation
- méthode automatique lisible par l'homme
.toString
sur les valeurs enum sans la nécessité de dupliquer vos noms enum -
.name
et.ordinal
méthodes spéciales - Utilisable dans les classes
EnumSet
etEnumMap
à base de bitset haute performance"
- les Énums sont traités par la langue spécialement:
- Enums utiliser une syntaxe spéciale qui simplifie la création d'instance sans écrire des dizaines de
public static final
champs - les Énumérations peuvent être utilisés dans les
switch
états - Enums ne peut être instancié en dehors de la liste d'énumération sauf en utilisant réflexion
- les Énumérations ne peut pas être étendu à l'extérieur de l'énumération de la liste
- Enums utiliser une syntaxe spéciale qui simplifie la création d'instance sans écrire des dizaines de
- Java compile automatiquement des éléments supplémentaires dans enums:
-
public static (Enum)[] values();
-
public static (Enum) valueOf(java.lang.String);
-
private static final (Enum)[] $VALUES;
(values()
renvoie un clone de ceci)
-
la plupart de ceux-ci peuvent être émulés avec un classe, mais Enum
rend juste vraiment facile de créer une classe avec cet ensemble de propriétés particulièrement désirables.
pour répondre à la question: essentiellement, il n'y a pas de différence entre les deux approches. Cependant, enum construct vous fournit quelques méthodes supplémentaires de support comme values()
, valueOf()
, etc. que vous devez écrire vous-même avec l'approche de classe-avec-un-constructeur privé.
Mais oui, J'aime Comment Java enums sont la plupart du temps comme toutes les autres classes en Java, ils peuvent avoir des champs, des comportements, etc. Mais pour moi ce qui sépare les énums de la plaine les classes est l'idée que les enums sont des classes/types dont les instances/membres sont prédéterminés. Contrairement aux classes habituelles où vous pouvez créer n'importe quel nombre d'instances à partir de, enums limitent la création aux instances connues. Oui, comme vous l'avez illustré, vous pouvez également le faire avec des classes avec des constructeurs privés, mais enums juste rendre cela plus intuitif.
jetez un oeil à cette page de blog , il décrit comment Java enum
s sont compilés dans bytecode. Vous verrez qu'il y a un petit ajout par rapport à votre second échantillon de code, qui est un tableau d'objets Direction
appelé VALUES
. Ce tableau contient toutes les valeurs possibles pour votre enum, donc vous ne pourrez pas faire
new Direction(2, 2)
(par exemple en utilisant la réflexion) et ensuite utiliser comme une valeur valide Direction
.
de Plus, comme @Eng.Fouad explique correctement, vous n'avez pas values()
, valueOf()
et ordinal()
.
comme les gens ont souligné vous perdez values()
, valueOf()
et ordinal()
. Vous pouvez reproduire ce comportement assez facilement en utilisant une combinaison d'un Map
et un List
.
public class Direction {
public static final Direction UP = build("UP", 0, -1);
public static final Direction DOWN = build("DOWN", 0, 1);
public static final Direction LEFT = build("LEFT", -1, 0);
public static final Direction RIGHT = build("RIGHT", 1, 0);
private static final Map<String, Direction> VALUES_MAP = new LinkedHashMap<>();
private static final List<Direction> VALUES_LIST = new ArrayList<>();
private final int x;
private final int y;
private final String name;
public Direction(int x, int y, String name) {
this.x = x;
this.y = y;
this.name = name;
}
private static Direction build(final String name, final int x, final int y) {
final Direction direction = new Direction(x, y, name);
VALUES_MAP.put(name, direction);
VALUES_LIST.add(direction);
return direction;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public static Direction[] values() {
return VALUES_LIST.toArray(new Direction[VALUES_LIST.size()]);
}
public static Direction valueOf(final String direction) {
if (direction == null) {
throw new NullPointerException();
}
final Direction dir = VALUES_MAP.get(direction);
if (dir == null) {
throw new IllegalArgumentException();
}
return dir;
}
public int ordinal() {
return VALUES_LIST.indexOf(this);
}
@Override
public int hashCode() {
int hash = 7;
hash = 29 * hash + name.hashCode();
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Direction other = (Direction) obj;
return name.equals(other.name);
}
@Override
public String toString() {
return name;
}
}
Comme vous pouvez le voir, le code devient très maladroit, très rapidement.
Je ne suis pas sûr qu'il y ait un moyen de répliquer une déclaration switch
avec cette classe; donc vous perdrez cela.
la principale différence est que la classe enum
s'étend implicitement à la classe Enum<E extends Enum<E>>
. Cela conduit à cela:
-
enum
objets ont des méthodes telles quename()
etordinal()
-
enum
les objets ont spécialtoString()
,hashCode()
,equals()
etcompareTo()
implémentations -
enum
les objets sont appropriés pour l'opérateurswitch
.
Direction
toutes les mentions ci-dessus ne s'appliquent pas à votre version de la classe Direction
. C'est le "sens" de la différence.