我正在尝试找到一种在使用泛型时迭代枚举值的方法。不知道如何做到这一点或是否有可能。
以下代码说明了我想要做的事情。请注意,代码 T.values()在以下代码中无效。
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);
}
}
}
以下是我将如何实例化Filter对象:
Filter<TimePeriod> filter = new Filter<TimePeriod>(TimePeriod.ALL);
枚举定义如下:
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;
}
}
我意识到将枚举值复制到列表可能没有意义,但我使用的是需要值列表作为输入的库,并且不能用于枚举。
EDIT 2/5/2010:
提出的大多数答案非常相似,建议做这样的事情:
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);
}
}
}
如果我可以确定selectedOption具有非null值,那么这将很有用。不幸的是,在我的用例中,这个值通常为null,因为还有一个 public Filter() no-arg构造函数。这意味着我无法在不获取NPE的情况下执行selectedOption.getClass()。此过滤器类管理可用选项的列表,其中选择了哪些选项。如果未选择任何内容,则selectedOption为空。
我能想到解决这个问题的唯一方法就是在构造函数中实际传入一个Class。所以像这样:
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);
}
}
}
如何在构造函数中不需要额外的Class参数的情况下如何做到这一点?
答案 0 :(得分:102)
这确实是一个难题。您需要做的一件事是告诉java您正在使用枚举。这是通过声明为您的泛型扩展Enum类。但是这个类没有values()函数。因此,您必须选择可以获得值的类。
以下示例可帮助您解决问题:
public <T extends Enum<T>> void enumValues(Class<T> enumType) {
for (T c : enumType.getEnumConstants()) {
System.out.println(c.name());
}
}
答案 1 :(得分:9)
另一种选择是使用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);
}
}
答案 2 :(得分:5)
为了完整性,JDK8为我们提供了一种相对简洁,更简洁的方法来实现这一目标,而无需在Enum类中使用合成values()
:
给出一个简单的枚举:
private enum TestEnum {
A,
B,
C
}
测试客户:
@Test
public void testAllValues() {
System.out.println(collectAllEnumValues(TestEnum.class));
}
这将打印{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(", " , "\"{", "}\""));
}
代码可以简单地适用于检索不同的元素或以不同的方式收集。
答案 3 :(得分:4)
使用不安全的演员:
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);
}
}
}
答案 4 :(得分:1)
如果您确定构造函数selectedOption
的{{1}}不为空。你可以使用反射。像这样。
Filter(T selectedOption)
希望这有帮助。
答案 5 :(得分:0)
根本问题是您需要将数组转换为列表,对吧?您可以通过使用特定类型(TimePeriod而不是T)和以下代码来执行此操作。
所以使用这样的东西:
List<TimePeriod> list = new ArrayList<TimePeriod>();
list.addAll(Arrays.asList(sizes));
现在您可以将列表传递给任何想要列表的方法。
答案 6 :(得分:0)
如果您将过滤器声明为
public class Filter<T extends Iterable>
然后
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();
}
};
}
}
使用非常简单:
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());
}
}
}
答案 7 :(得分:0)
下面是Enum周围的包装类示例。 有点奇怪,我需要的是:
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;
}
}
答案 8 :(得分:0)
获取通用枚举的值:
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));
}
注意在上面的方法中调用toString()方法。
然后用这样的toString()方法定义枚举。
public enum MyNameEnum {
MR("John"), MRS("Anna");
private String name;
private MyNameEnum(String name) {
this.name = name;
}
public String toString() {
return this.name;
}
}
答案 9 :(得分:0)
我是这样做的
protected List<String> enumToList(Class<? extends Enum<?>> e) {
Enum<?>[] enums = e.getEnumConstants();
return Arrays.asList(enums).stream()
.map(name -> name.toString())
.collect(Collectors.toList());
}