使用java泛型迭代枚举值

Tau*_*ren 66 java generics enums enumeration

我正在尝试找到一种在使用泛型时迭代枚举值的方法.不知道如何做到这一点或是否有可能.

以下代码说明了我想要做的事情.请注意,代码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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是我将如何实例化Filter对象:

Filter<TimePeriod> filter = new Filter<TimePeriod>(TimePeriod.ALL);
Run Code Online (Sandbox Code Playgroud)

枚举定义如下:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我意识到将枚举值复制到列表可能没有意义,但我使用的是需要值列表作为输入的库,而不能使用枚举.


编辑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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我可以确定selectedOption具有非null值,那么这将很有用.不幸的是,在我的用例中,这个值通常为null,因为还有一个公共的Filter() no-arg构造函数.这意味着我无法在不获取NPE的情况下执行selectedOption.getClass().此过滤器类管理可用选项的列表,其中选择了哪些选项.如果未选择任何内容,则selectedOption为null.

我能想到解决这个问题的唯一方法就是在构造函数中实际传入一个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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

有没有想法如何在构造函数中不需要额外的Class参数?

Thi*_*ler 109

这确实是一个难题.您需要做的一件事是告诉java您正在使用枚举.这是通过声明为您的泛型扩展Enum类.但是这个类没有values()函数.因此,您必须选择可以获取值的类.

以下示例可帮助您解决问题:

public <T extends Enum<T>> void enumValues(Class<T> enumType) {
        for (T c : enumType.getEnumConstants()) {
             System.out.println(c.name());
        }
}
Run Code Online (Sandbox Code Playgroud)


Mis*_*ble 11

另一种选择是使用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);
    } 

}
Run Code Online (Sandbox Code Playgroud)


Boz*_*zho 5

使用不安全的强制转换:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


qua*_*tum 5

为了完整起见,JDK8为我们提供了一种相对简洁,更简洁的方法来实现这一点,而无需values()在Enum类中使用合成:

给出一个简单的枚举:

private enum TestEnum {
    A,
    B,
    C
}
Run Code Online (Sandbox Code Playgroud)

和测试客户:

@Test
public void testAllValues() {
    System.out.println(collectAllEnumValues(TestEnum.class));
}
Run Code Online (Sandbox Code Playgroud)

这将打印{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(", " , "\"{", "}\""));
}
Run Code Online (Sandbox Code Playgroud)

代码可以简单地适用于检索不同的元素或以不同的方式收集.