J'essaie de trouver un moyen de parcourir les valeurs d'une énumération en utilisant des génériques. Vous ne savez pas comment faire cela ou si c'est possible.
Le code suivant illustre ce que je veux faire. Notez que le code T.values () n'est pas valide dans le code suivant.
public class Filter<T> {
private List<T> availableOptions = new ArrayList<T>();
private T selectedOption;
public Filter(T selectedOption) {
this.selectedOption = selectedOption;
for (T option : T.values()) { // INVALID CODE
availableOptions.add(option);
}
}
}
Voici comment instancier un objet filtre:
Filter<TimePeriod> filter = new Filter<TimePeriod>(TimePeriod.ALL);
L'énumération est définie comme suit:
public enum TimePeriod {
ALL("All"),
FUTURE("Future"),
NEXT7DAYS("Next 7 Days"),
NEXT14DAYS("Next 14 Days"),
NEXT30DAYS("Next 30 Days"),
PAST("Past"),
LAST7DAYS("Last 7 Days"),
LAST14DAYS("Last 14 Days"),
LAST30DAYS("Last 30 Days");
private final String name;
private TimePeriod(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
Je me rends bien compte que cela n’a pas de sens de copier les valeurs d’une énumération dans une liste, mais j’utilise une bibliothèque qui nécessite une liste de valeurs en entrée et ne fonctionne pas avec des énumérations.
EDIT 2/5/2010:
La plupart des réponses proposées sont très similaires et suggèrent de faire quelque chose comme ceci:
class Filter<T extends Enum<T>> {
private List<T> availableOptions = new ArrayList<T>();
private T selectedOption;
public Filter(T selectedOption) {
Class<T> clazz = (Class<T>) selectedOption.getClass();
for (T option : clazz.getEnumConstants()) {
availableOptions.add(option);
}
}
}
Cela fonctionnerait très bien si je peux être sûr que selectedOption a une valeur non nulle. Malheureusement, dans mon cas d'utilisation, cette valeur est souvent nulle, car il existe également un constructeur public Filter () no-arg. Cela signifie que je ne peux pas faire de selectedOption.getClass () sans obtenir un NPE. Cette classe de filtre gère une liste d'options disponibles, laquelle des options est sélectionnée. Lorsque rien n'est sélectionné, selectedOption est null.
La seule chose à laquelle je peux penser pour résoudre ce problème est de passer réellement une classe dans le constructeur. Donc, quelque chose comme ça:
class Filter<T extends Enum<T>> {
private List<T> availableOptions = new ArrayList<T>();
private T selectedOption;
public Filter(Class<T> clazz) {
this(clazz,null);
}
public Filter(Class<T> clazz, T selectedOption) {
this.selectedOption = selectedOption;
for (T option : clazz.getEnumConstants()) {
availableOptions.add(option);
}
}
}
Des idées comment faire cela sans avoir besoin d'un paramètre de classe supplémentaire dans les constructeurs?
C'est un problème difficile en effet. Une des choses à faire est de dire à Java que vous utilisez une énumération. C'est en déclarant que vous étendez la classe Enum pour vos génériques. Cependant, cette classe n'a pas la fonction values (). Vous devez donc suivre le cours pour lequel vous pouvez obtenir les valeurs.
L'exemple suivant devrait vous aider à résoudre votre problème:
public <T extends Enum<T>> void enumValues(Class<T> enumType) {
for (T c : enumType.getEnumConstants()) {
System.out.println(c.name());
}
}
Une autre option consiste à utiliser EnumSet:
class PrintEnumConsants {
static <E extends Enum <E>> void foo(Class<E> elemType) {
for (E e : Java.util.EnumSet.allOf(elemType)) {
System.out.println(e);
}
}
enum Color{RED,YELLOW,BLUE};
public static void main(String[] args) {
foo(Color.class);
}
}
Pour être complet, JDK8 nous offre un moyen relativement propre et plus concis d’y parvenir sans avoir à utiliser la fonction synthétique values()
dans la classe Enum:
Donné une simple énumération:
private enum TestEnum {
A,
B,
C
}
Et un client test:
@Test
public void testAllValues() {
System.out.println(collectAllEnumValues(TestEnum.class));
}
Ceci imprimera {A, B, C}
:
public static <T extends Enum<T>> String collectAllEnumValues(Class<T> clazz) {
return EnumSet.allOf(clazz).stream()
.map(Enum::name)
.collect(Collectors.joining(", " , "\"{", "}\""));
}
Le code peut être adapté de manière triviale pour récupérer différents éléments ou pour les collecter de manière différente.
En utilisant un casting dangereux:
class Filter<T extends Enum<T>> {
private List<T> availableOptions = new ArrayList<T>();
private T selectedOption;
public Filter(T selectedOption) {
Class<T> clazz = (Class<T>) selectedOption.getClass();
for (T option : clazz.getEnumConstants()) {
availableOptions.add(option);
}
}
}
Si vous êtes sûr que selectedOption
du constructeur Filter(T selectedOption)
n'est pas null. Vous pouvez utiliser la réflexion. Comme ça.
public class Filter<T> {
private List<T> availableOptions = new ArrayList<T>();
private T selectedOption;
public Filter(T selectedOption) {
this.selectedOption = selectedOption;
for (T option : this.selectedOption.getClass().getEnumConstants()) { // INVALID CODE
availableOptions.add(option);
}
}
}
J'espère que cela t'aides.
Le problème fondamental est que vous devez convertir un tableau en liste, n'est-ce pas? Vous pouvez le faire en utilisant un type spécifique (TimePeriod au lieu de T) et le code suivant.
Alors utilisez quelque chose comme ceci:
List<TimePeriod> list = new ArrayList<TimePeriod>();
list.addAll(Arrays.asList(sizes));
Maintenant, vous pouvez passer liste dans n'importe quelle méthode qui veut une liste.
Si vous déclarez le filtre en tant que
public class Filter<T extends Iterable>
puis
import Java.util.Iterator;
public enum TimePeriod implements Iterable {
ALL("All"),
FUTURE("Future"),
NEXT7DAYS("Next 7 Days"),
NEXT14DAYS("Next 14 Days"),
NEXT30DAYS("Next 30 Days"),
PAST("Past"),
LAST7DAYS("Last 7 Days"),
LAST14DAYS("Last 14 Days"),
LAST30DAYS("Last 30 Days");
private final String name;
private TimePeriod(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
public Iterator<TimePeriod> iterator() {
return new Iterator<TimePeriod>() {
private int index;
@Override
public boolean hasNext() {
return index < LAST30DAYS.ordinal();
}
@Override
public TimePeriod next() {
switch(index++) {
case 0 : return ALL;
case 1 : return FUTURE;
case 2 : return NEXT7DAYS;
case 3 : return NEXT14DAYS;
case 4 : return NEXT30DAYS;
case 5 : return PAST;
case 6 : return LAST7DAYS;
case 7 : return LAST14DAYS;
case 8 : return LAST30DAYS;
default: throw new IllegalStateException();
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
Et l'utilisation est assez facile:
public class Filter<T> {
private List<T> availableOptions = new ArrayList<T>();
private T selectedOption;
public Filter(T selectedOption) {
this.selectedOption = selectedOption;
Iterator<TimePeriod> it = selectedOption.iterator();
while(it.hasNext()) {
availableOptions.add(it.next());
}
}
}
Voici ci-dessous un exemple de classe wrapper autour d'un Enum . C'est un peu bizarre mais c'est ce dont j'ai besoin:
public class W2UIEnum<T extends Enum<T> & Resumable> {
public String id;
public String caption;
public W2UIEnum(ApplicationContext appContext, T t) {
this.id = t.getResume();
this.caption = I18N.singleInstance.getI18nString(t.name(), "enum_"
+ t.getClass().getSimpleName().substring(0, 1).toLowerCase()
+ t.getClass().getSimpleName().substring(1,
t.getClass().getSimpleName().length()), appContext
.getLocale());
}
public static <T extends Enum<T> & Resumable> List<W2UIEnum<T>> values(
ApplicationContext appContext, Class<T> enumType) {
List<W2UIEnum<T>> statusList = new ArrayList<W2UIEnum<T>>();
for (T status : enumType.getEnumConstants()) {
statusList.add(new W2UIEnum(appContext, status));
}
return statusList;
}
}
Pour obtenir le valeur de l'énumération générique:
protected Set<String> enum2set(Class<? extends Enum<?>> e) {
Enum<?>[] enums = e.getEnumConstants();
String[] names = new String[enums.length];
for (int i = 0; i < enums.length; i++) {
names[i] = enums[i].toString();
}
return new HashSet<String>(Arrays.asList(names));
}
Notez dans la méthode ci-dessus l'appel à la méthode toString ().
Et ensuite définir l'énumération avec une telle méthode toString ().
public enum MyNameEnum {
MR("John"), MRS("Anna");
private String name;
private MyNameEnum(String name) {
this.name = name;
}
public String toString() {
return this.name;
}
}