使用Javagenerics迭代枚举值
我试图find一种方法来遍历枚举的值,而使用generics。 不知道如何做到这一点,如果可能的话。
下面的代码演示了我想要做什么。 请注意代码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; } }
我意识到将枚举的值复制到列表中可能没有意义,但是我使用的库需要一个值列表作为input,并且不能使用枚举。
编辑2/5/2010:
大部分提出的答案都非常相似,并build议做这样的事情:
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有一个非空值,这将工作得很好。 不幸的是,在我的用例中,这个值通常是空的,因为还有一个公共的Filter() no-arg构造函数。 这意味着我不能做一个selectedOption.getClass()没有得到一个NPE。 此筛选器类pipe理可用选项的列表,select哪个选项。 当没有select时,selectedOption为null。
我唯一能想到的解决办法就是在构造函数中传入一个类。 所以像这样的东西:
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); } } }
任何想法如何做到这一点,而不需要在构造函数中额外的类参数?
这确实是一个难题。 你需要做的事情之一是告诉java你正在使用枚举。 这是说,你扩展了generics类的generics。 但是这个类没有values()函数。 所以你必须拿到你能获得价值的课程。
下面的例子可以帮助你解决你的问题:
public <T extends Enum<T>> void enumValues(Class<T> enumType) { for (T c : enumType.getEnumConstants()) { System.out.println(c.name()); } }
另一种select是使用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); } }
使用不安全的演员:
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); } } }
为了完整起见,JDK8给了我们一个相对简洁而又简洁的方法来实现这一点,而不需要在Enum类中使用合成values()
:
给定一个简单的枚举:
private enum TestEnum { A, B, C }
和一个testing客户端:
@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(", " , "\"{", "}\"")); }
代码可以简单地适用于检索不同的元素或以不同的方式收集。
如果您确定构造函数Filter(T selectedOption)
不为null。 你可以使用reflection。 喜欢这个。
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); } } }
希望这可以帮助。
根本问题是你需要将数组转换为列表,对吧? 您可以通过使用特定types(TimePeriod而不是T)和下面的代码来完成此操作。
所以使用这样的东西:
List<TimePeriod> list = new ArrayList<TimePeriod>(); list.addAll(Arrays.asList(sizes));
现在,您可以将列表传递给想要列表的任何方法。
如果你声明过滤为
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()); } } }
下面是一个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; }
}
为了得到generics枚举的值 :
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; } }