如何从通用枚举类型中检索常量的接口?

时间:2014-08-12 11:14:31

标签: java generics interface enums

我设计了一个方法的参数,对于一个必须处理泛型枚举的类(我的意思是,该类可以是库的一部分,用户将使用用户定义的枚举提供该类方法,正在设计的类不知道其特定类型 - 让我们将此类称为“库类”。)

我希望尽可能在语法上约束该参数类型,以便只允许正确的类型。

我的要求是类型必须是实现特定接口的枚举EnumKind

public interface EnumKind {

    String getText();

}

到目前为止,我已经能够写出这种类型了:

Class<? extends Enum<? extends EnumKind>> t;

通过该声明,并具有以下内容:

public enum MyEnumKind implements EnumKind {

    // ...

    public String getText() {
        // TODO Auto-generated method stub
        return null;
    }

}

public class MyClassKind implements EnumKind {

    @Override
    public String getText() {
        // TODO Auto-generated method stub
        return null;
    }

}

public enum MyEnum {

}

只有t = MyEnumKind.class是正确的,其他任务(如t = MyClassKind.class)会被编译器拒绝,这就是我想要的行为。

现在,在我的方法体内,我可以成功地做到:

Enum<? extends EnumKind>[] tt = t.getEnumConstants();

但是我还没有找到直接检索EnumKind的方法来访问每个枚举常量getText()方法。

如何在没有显式转换的情况下获取EnumKind元素数组?这种类型的声明是我能写的最好的,还是我可以改进它? 如果无法避免显式强制转换,那么类型声明是否可以100%安全地避免抛出任何ClassCastException(或任何类似异常)的可能性?


修改


我会详细说明一下,因为我正在打另一个路障。

EnumKind接口要求枚举将字符串与每个枚举常量相关联,即:

public enum MyEnumKind implements EnumKind {

    A("#A#"),
    B("#B#"),
    C("#C#");

    private String text;

    private Token(String text) {
        this.text = text;
    }

    @Override
    public String getText() {
        return text;
    }

}

接下来,我想检索对应于特定字符串的枚举常量,例如

? enumValue = getValueFor("#A#");

enumValue(它应该是什么类型?)应该代表MyEnumKind.A,并且不需要知道实际值,因为enumValue将被传递给另一个方法。

我设计了这样的库类(在@JoopEggen回答之后):

public class EnumManager<T extends Enum<?> & EnumKind> {

    private Class<T> en;

    public EnumManager(Class<T> en) {
        this.en = en;
    }

   protected ? getValueFor(String s) {
        for(EnumKind ek : en.getEnumConstants()) {
            if(s.equals(ek.getText())) {
                // I found the enum constant I need... and now?
                return ? ;
            }
        }

    }

    //...

我该如何填写该代码?

3 个答案:

答案 0 :(得分:0)

是的,它是安全的,因为Number[]Integer[]的超类(与List<Number>相反而不是是{{1}的超类})。

因此,如果声明的组件类型List<Integer>tt的元素的声明类型)实现tt,则此类元素的数组会扩展EnumKind,因此这是安全

EnumKind[]

您没有收到任何警告,因为这是安全的,您永远不会得到EnumKind[] tt = (EnumKind[]) t.getEnumConstants(); // Casting to superclass: OK

答案 1 :(得分:0)

使用.getText T必须&#34;延伸&#34; EnumKind也是。 Enum包装器不提供此功能。

public static class MyC<T extends Enum<?> & EnumKind> {
    public void f(T t) {
        System.out.println("-> " + t.getText());
    }
}

在上方,您会看到extends CLASS & INTERFACE。额外的界限必须是接口。


问题编辑后:

protected T getValueFor(String s) {
    for (T t : en.getEnumConstants()) {
        if (s.equals(ek.getText())) {
            return t;
        }
    }
}

使用静态HashMap可能会更好。

我担心整个代码可能会过度设计。最好遵循一个简单的设计,有太多的工件。

你需要像AbstractEnum这样的东西,从

中抽象出来
public enum EnumABC {
    A("a"), B("b"), C("c");

    private static final Map<String, EnumABC> textToEnum = new HashMap<>();
    static {
        for (EnumABC value : values()) {
            EnumABC oldValue = textToEnum.put(value.text, value);
            if (oldValue != null) {
                throw new IllegalArgumentException(
                        String.format("Enum %s: same value %s for %s and %s",
                                value.getClass().getName(),
                                value.text,
                                oldValue,
                                value));
            }
        }
    }

    public static EnumABC fromText(String text) {
        EnumABC value = textToEnum.get(text);
        return value;
    }

    private final String text;

    private EnumABC(String text) {
        this.text = text;
    }
}
祝你好运。

<强> 简单:

@Override
public String getText() {
    String s = toString();
    return "#" + s.replace('_', ' ') + "#";
}

答案 2 :(得分:0)

通用方法怎么样:

static <T extends Enum<T> & EnumKind> T helper(Class<T> t, String s) {
    EnumKind[] tt = t.getEnumConstants();
    // do what you need to do here
}
相关问题