Ich versuche einen Weg zu finden, um die Werte einer Aufzählung zu durchlaufen, während Generika verwendet werden. Ich bin mir nicht sicher, wie ich das machen soll oder ob es möglich ist.
Der folgende Code zeigt, was ich tun möchte. Beachten Sie, dass der Code T.values () im folgenden Code nicht gültig ist.
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);
}
}
}
So würde ich ein Filterobjekt instanziieren:
Filter<TimePeriod> filter = new Filter<TimePeriod>(TimePeriod.ALL);
Die Aufzählung ist wie folgt definiert:
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;
}
}
Mir ist klar, dass es möglicherweise nicht sinnvoll ist, die Werte einer Aufzählung in eine Liste zu kopieren, aber ich verwende eine Bibliothek, die eine Liste von Werten als Eingabe benötigt und nicht mit Aufzählungen funktioniert.
BEARBEITEN 05.02.2010:
Die meisten der vorgeschlagenen Antworten sind sehr ähnlich und schlagen Folgendes vor:
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);
}
}
}
Dies würde gut funktionieren, wenn ich sicher sein kann, dass selectedOption einen Wert ungleich Null hat. Leider ist dieser Wert in meinem Anwendungsfall oft null, da es auch einen öffentlichen Filter () no-arg-Konstruktor gibt. Dies bedeutet, dass ich eine selectedOption.getClass () nicht ausführen kann, ohne eine NPE zu erhalten. Diese Filterklasse verwaltet eine Liste der verfügbaren Optionen, welche der Optionen ausgewählt ist. Wenn nichts ausgewählt ist, ist selectedOption null.
Das einzige, was ich denken kann, um dies zu lösen, ist, tatsächlich eine Klasse im Konstruktor zu übergeben. Also so etwas wie das:
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);
}
}
}
Haben Sie Ideen, wie Sie dies tun können, ohne einen zusätzlichen Klassenparameter in den Konstruktoren zu benötigen?
quelle
getClass
Code schlägt auch fehl, wenn die Enum-Konstante eine anonyme Unterklasse ist ( Beispiel ).getDeclaringClass
sollte stattdessen verwendet werden.Antworten:
Dies ist in der Tat ein schwieriges Problem. Eines der Dinge, die Sie tun müssen, ist Java mitzuteilen, dass Sie eine Aufzählung verwenden. Dies geschieht, indem Sie angeben, dass Sie die Enum-Klasse für Ihre Generika erweitern. Diese Klasse hat jedoch nicht die Funktion values (). Sie müssen also die Klasse nehmen, für die Sie die Werte erhalten können.
Das folgende Beispiel soll Ihnen helfen, Ihr Problem zu beheben:
public <T extends Enum<T>> void enumValues(Class<T> enumType) { for (T c : enumType.getEnumConstants()) { System.out.println(c.name()); } }
quelle
getFriendlyName()
. Dann müssten Sie Ihrer Aufzählung eine Schnittstelle hinzufügen und dann die oben genannten Generika anpassen, um sowohl eine Aufzählung als auch die Schnittstelle für den Typ zu benötigenT
. Die Funktion wird dann so etwas wie:public <E extends Enum<?> & EnumWithFriendlyName> void friendlyEnumValues(Class<T> enumType)
Eine andere Option ist die Verwendung von 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); } }
quelle
Der Vollständigkeit halber bietet JDK8 eine relativ saubere und präzisere Möglichkeit, dies zu erreichen, ohne die Synthethik verwenden zu müssen
values()
in der Enum-Klasse verwenden zu müssen:Bei einer einfachen Aufzählung:
private enum TestEnum { A, B, C }
Und ein Testclient:
@Test public void testAllValues() { System.out.println(collectAllEnumValues(TestEnum.class)); }
Dies wird gedruckt
{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(", " , "\"{", "}\"")); }
Code kann trivial angepasst werden, um verschiedene Elemente abzurufen oder auf andere Weise zu sammeln.
quelle
Verwenden einer unsicheren Besetzung:
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); } } }
quelle
getClass
schlägt fehl, wenn die Enum-Konstante eine anonyme Unterklasse ist ( Beispiel ).getDeclaringClass
sollte stattdessen verwendet werden.Wenn Sie sicher sind, dass
selectedOption
der KonstruktorFilter(T selectedOption)
nicht null ist. Sie können Reflexion verwenden. So was.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); } } }
Hoffe das hilft.
quelle
So ermitteln Sie den Wert der generischen Aufzählung:
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)); }
Beachten Sie in der obigen Methode den Aufruf der toString () -Methode.
Und dann definieren Sie die Aufzählung mit einer solchen toString () -Methode.
public enum MyNameEnum { MR("John"), MRS("Anna"); private String name; private MyNameEnum(String name) { this.name = name; } public String toString() { return this.name; } }
quelle
Das Hauptproblem ist, dass Sie ein Array in eine Liste konvertieren müssen, oder? Sie können dies tun, indem Sie einen bestimmten Typ (TimePeriod anstelle von T) und den folgenden Code verwenden.
Verwenden Sie also so etwas:
List<TimePeriod> list = new ArrayList<TimePeriod>(); list.addAll(Arrays.asList(sizes));
Jetzt können Sie die Liste an jede Methode übergeben, die eine Liste haben möchte.
quelle
Wenn Sie Filter als deklarieren
public class Filter<T extends Iterable>
dann
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(); } }; } }
Und die Verwendung ist ganz einfach:
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()); } } }
quelle
Hier unten ein Beispiel einer Wrapper-Klasse um eine Aufzählung. Ist ein bisschen komisch bu ist was ich brauche:
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; }
}}
quelle
Ich habe es so gemacht
protected List<String> enumToList(Class<? extends Enum<?>> e) { Enum<?>[] enums = e.getEnumConstants(); return Arrays.asList(enums).stream() .map(name -> name.toString()) .collect(Collectors.toList()); }
quelle