2010-01-13 5 views
7

Est-ce que Java permet quelque chose comme du bon vieux C ou même C# dans le sens où vous pouvez définir une énumération avec des champs qui grandissent automatiquement et commencer à une valeur donnée?Entrées auto-incrémentées Java enum?

E.g.

en C ou C#:

enum Foo { A = 10, B, C, D = 5000, E, Fish }; 

Rendements A = 10, B = 11, C = 12, D = 5000, E = 5001, Poisson = 5002.

Répondre

10

En Java, vous pouvez » t spécifiez explicitement les valeurs ordinales . Ils s'autoincrément toujours, à partir de 0, sans aucun contrôle sur elle.

Si vous voulez d'autres valeurs personnalisées, vous devez les placer dans des appels de constructeur et les stocker vous-même. Vous pouvez obtenir autoincrement, mais il est dégueu que diable:

import java.util.EnumSet; 

// Please don't ever use this code. It's here so you can point and laugh. 
enum Foo 
{ 
    A(10), B, C, D(5000), E, Fish; 

    private static int nextValue; 
    private int value; 

    private Foo() 
    { 
     this(Counter.nextValue); 
    } 

    private Foo(int value) 
    { 
     this.value = value; 
     Counter.nextValue = value + 1; 
    } 

    public int getValue() 
    { 
     return value; 
    } 

    private static class Counter 
    { 
     private static int nextValue = 0; 
    } 
} 

public class Test 
{ 
    public static void main(String[] args) 
    { 
     for (Foo foo : EnumSet.allOf(Foo.class)) 
     { 
      System.out.println(foo.name() + " " + 
           foo.ordinal() + " " + 
           foo.getValue()); 
     } 
    } 
} 

Notez la nécessité pour la classe imbriquée, parce que vous ne pouvez pas accéder aux champs statiques dans un constructeur ENUM. Ick, ick, ick. S'il vous plaît ne faites pas ça.

+0

'Il est ici, donc vous pouvez pointer et laugh.' Haha. Un bon! –

+0

le constructeur par défaut doit mettre à jour Counter.nextValue, et vous pouvez probablement supprimer nextValue directement dans Foo. – Yuliy

+0

@Yuliy: Le constructeur sans paramètre appelle celui paramétré, ce qui met à jour Counter.nextValue. Mettre nextValue directement dans Foo * ne fonctionne pas - du moins pas avec la version de javac que j'utilise. Cela vous empêche d'accéder aux champs statiques dans le constructeur. –

10

Ceci est un choix de conception de Java Enums pour ne pas prendre en charge la modification des valeurs ordinales. Fondamentalement, ils sont pas stable assez pour en dépendre. Si vous changez la position de B et C dans votre exemple, les clients dépendant des valeurs ordinales sont cassés. Cela peut arriver involontairement.

Le problème est décrit dans Effective Java Item 31: Use instance field instead of ordinals.

Vous pouvez imiter le comportement d'une manière stable:

enum X{ 
    A(10), B(A), C(B), D(5000), E(D), F(E); 

    private final int value; 

    X(int value){ 
     this.value = value; 
    } 

    X(X preceding){ 
     this.value = preceding.getValue() + 1; 
    } 

    public int getValue() { 
     return value; 
    } 

    @Override 
    public String toString() { 
     return this.name() + "(" + this.value + ")"; 
    } 

    static { 
     Set<Integer> values = new HashSet<Integer>(); 
     for(X x : X.values()) values.add(x.value); 
     assert(values.size() == X.values().length); //no duplicates 
    } 
} 

Avec cette définition, vous pouvez changer l'ordre des valeurs sans casser les clients.

Appel for(X x : X.values()) System.out.println(x); Retours:

A(10) 
B(11) 
C(12) 
D(5000) 
E(5001) 
F(5002) 
+0

Kinda craint cependant - ils ont leurs utilisations. Par exemple quand je ne veux pas que mes énumérations aient des valeurs inférieures à N, par exemple (peut-être que je veux réserver cette plage pour être hors-limites). Mais je ne veux pas non plus définir manuellement chaque valeur entière moi-même ... –

+0

@alex: cela signifie que vous devriez avoir un champ, qui calcule le nombre à partir de l'ordinal, étant donné les contraintes de la plage que vous voulez. – Chii

+0

@Alex - La version émulée devrait fonctionner pour vous. C'est stable et vous n'avez pas besoin de mettre chaque valeur int explicitement. –