58 votes

Quelles sont les différences entre une énumération Java et une classe avec constructeur privé?

J'essayais de comprendre comment enum de Java qui fonctionne vraiment et j'en suis venu à la conclusion qui est très similaire à une normale de la classe Java qui a son constructeur a déclaré privé.

Je viens d'en venir à cette conclusion, et il n'est pas basé sur beaucoup de réflexion, mais j'aimerai savoir si j'ai manqué de rien.

Donc, ci-dessous est une implémentation de Java simple enum et un équivalent de la classe Java.

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 sens entre le code ci-dessus et 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;
    }
}

59voto

nneonneo Points 56821

Différences:

  1. Les Enums étendre java.lang.Enum et le gain de l'ensemble de ses fonctionnalités intéressantes:
    1. Automatique singleton comportement grâce à un bon de sérialisation
    2. Automatique lisible par l'homme, .toString méthode sur les valeurs de l'enum sans la nécessité de dupliquer vos noms enum
    3. .name et .ordinal spéciaux méthodes
    4. Utilisable en haute-performance bitset-fondé EnumSet et EnumMap classes
  2. Les énumérations sont traités par la langue, spécialement:
    1. Les Enums utiliser une syntaxe particulière qui simplifie la création de l'instance sans avoir à écrire des dizaines de public static final champs
    2. Les énumérations peuvent être utilisés en switch des déclarations
    3. Les énumérations ne peut pas être instanciée à l'extérieur de l'énumération de la liste, sauf par l'aide de la réflexion
    4. Les énumérations ne peut pas être étendu à l'extérieur de l'énumération de la liste
  3. Java compile automatiquement les trucs supplémentaires dans les énumérations:
    1. public static (Enum)[] values();
    2. public static (Enum) valueOf(java.lang.String);
    3. private static final (Enum)[] $VALUES; (values() retourne un clone de ce)

La plupart de ces peut être émulée avec un bien conçu classe, mais Enum seulement, il est vraiment facile de créer une classe avec cet ensemble de particulièrement propriétés souhaitables.

10voto

Psycho Punch Points 400

Pour répondre à la question: essentiellement, il n'y a pas de différence entre les deux approches. Cependant, enum construire vous donne quelques supplémentaires sur les méthodes comme values(), valueOf(), etc. qui que vous auriez à écrire sur votre propre avec la classe-avec-privé-constructeur approche.

Mais ouais, j'aime la façon dont Java enums sont pour la plupart juste comme toutes les autres classes en Java, ils peuvent avoir des champs, les comportements, etc. Mais pour moi, ce qui sépare les énumérations de la plaine des classes, c'est l'idée que les énumérations sont des classes/types dont les instances et les membres sont déterminés à l'avance. Contrairement à l'habitude des cours où vous pouvez créer un nombre illimité d'instances de, les énumérations seule limite à la création d'instances connues. Oui, comme vous l'avez illustré, vous pouvez également le faire avec des classes avec les constructeurs privés, mais les énumérations, juste de la rendre plus intuitive.

7voto

mthmulders Points 4590

Jetez un oeil à cette blogpage, il décrit comment Java enums sont compilés en bytecode. Vous verrez que il y a un petit plus par rapport à votre deuxième exemple de code, qui est un tableau d' Direction des objets appelés VALUES. Ce tableau contient toutes les valeurs possibles pour votre enum, de sorte que vous ne serez pas en mesure de le faire

new Direction(2, 2)

(par exemple à l'aide de la réflexion), et ensuite de l'utiliser comme valide Direction de la valeur.

De Plus, comme @Eng.Fouad correctement explique, vous n'avez pas d' values(), valueOf() et ordinal().

5voto

Boris the Spider Points 20200

Comme les gens l'ont souligné, vous perdez values() , valueOf() et ordinal() . Vous pouvez reproduire ce problème assez facilement en combinant Map et 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 sais pas s'il est possible de répliquer une instruction switch avec cette classe; alors vous allez perdre ça.

0voto

Andremoniy Points 7349

La principale différence est la chaque enum classe implicitement s'étend Enum<E extends Enum<E>> classe. Cela conduit à ce que:

  1. enum des objets ont des méthodes telles que l' name() et ordinal()
  2. enum objets spéciaux toString(), hashCode(), equals() et compareTo() des implémentations
  3. enum des objets sont appropriés pour l' switch de l'opérateur.

Tout ce qui est mentionné ci-dessus n'est pas applicable pour votre version de Direction classe. C'est le "sens" de la différence.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X