使用 java 泛型迭代枚举值
我试图找到一种在使用泛型时迭代枚举值的方法。不确定如何执行此操作或是否可能。
下面的代码说明了我想要做的事情。请注意,代码 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;
}
}
我意识到将枚举的值复制到列表可能没有意义,但我正在使用一个需要值列表作为输入并赢得的库不适用于枚举。
编辑 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 有一个非空值,这将非常有用。不幸的是,在我的用例中,该值通常为空,因为还有一个 public Filter() 无参数构造函数。这意味着我无法在没有获得 NPE 的情况下执行 selectedOption.getClass() 。该过滤器类管理可用选项的列表,其中的选项被选中。当未选择任何内容时,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);
}
}
}
有什么想法如何在构造函数中不需要额外的 Class 参数来做到这一点?
I'm trying to find a way to iterate through an enum's values while using generics. Not sure how to do this or if it is possible.
The following code illustrates what I want to do. Note that the code T.values() is not valid in the following code.
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);
}
}
}
Here is how I would instantiate a Filter object:
Filter<TimePeriod> filter = new Filter<TimePeriod>(TimePeriod.ALL);
The enum is defined as follows:
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;
}
}
I realize it might not make sense to copy a enum's values to a list, but I'm using a library that needs a list of values as input and won't work with enums.
EDIT 2/5/2010:
Most of the answers proposed are very similar and suggest doing something like this:
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);
}
}
}
This would work great if I can be sure that selectedOption has a non-null value. Unfortunately, in my use case, this value is often null, as there is a public Filter() no-arg constructor as well. This means I can't do a selectedOption.getClass() without getting an NPE. This filter class manages a list of available options which of the options is selected. When nothing is selected, selectedOption is null.
The only thing I can think to solve this is to actually pass in a Class in the constructor. So something like this:
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);
}
}
}
Any ideas how to do this without needing an extra Class parameter in the constructors?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
这确实是一个难题。您需要做的事情之一是告诉 java 您正在使用枚举。这是通过声明您为泛型扩展了 Enum 类。然而这个类没有values()函数。所以你必须参加能够获得数值的课程。
以下示例应该可以帮助您解决问题:
This is a hard problem indeed. One of the things you need to do is tell java that you are using an enum. This is by stating that you extend the Enum class for your generics. However this class doesn't have the values() function. So you have to take the class for which you can get the values.
The following example should help you fix your problem:
另一种选择是使用 EnumSet:
Another option is to use EnumSet:
为了完整起见,JDK8 为我们提供了一种相对干净且更简洁的方法来实现此目的,而无需在 Enum 类中使用合成
values()
:给定一个简单的枚举:
和一个测试客户端:
这将打印
{A, B, C}
:可以简单地修改代码以检索不同的元素或以不同的方式收集。
For completeness, JDK8 gives us a relatively clean and more concise way of achieving this without the need to use the synthethic
values()
in Enum class:Given a simple enum:
And a test client:
This will print
{A, B, C}
:Code can be trivially adapted to retrieve different elements or to collect in a different way.
使用不安全的强制转换:
Using an unsafe cast:
如果您确定构造函数
Filter(T selectedOption)
的selectedOption
不为 null。您可以使用反射。像这样。希望这有帮助。
If you are sure that
selectedOption
of the constructorFilter(T selectedOption)
is not null. You can use reflection. Like this.Hope this helps.
如果你将 Filter 声明为
then
并且用法非常简单:
If you declare Filter as
then
And usage is quite easy:
要获取通用枚举的值:
请注意上述方法中对 toString() 方法的调用。
然后用这样的toString()方法定义枚举。
To get the value of the generic enumeration:
Note in the above method the call to the toString() method.
And then define the enumeration with such a toString() method.
我是这样做的
I did it like this
根本问题是您需要将数组转换为列表,对吗?您可以通过使用特定类型(TimePeriod 而不是 T)和以下代码来执行此操作。
所以使用这样的东西:
现在你可以将列表传递到任何需要列表的方法中。
The root problem is that you need to convert an array to a list, right? You can do this, by using a specific type (TimePeriod instead of T), and the following code.
So use something like this:
Now you can pass list into any method that wants a list.
下面是围绕 Enum 的包装类的示例。
有点奇怪,但这正是我需要的:
}
Here below an example of a wrapper class around an Enum.
Is a little bit weird bu is what i need :
}