繁体   English   中英

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

[英]How do I retrieve the interface of the constants from a generic enum type?

我为一个必须处理通用枚举的类指定一个方法的参数(我的意思是,该类可能是库的一部分,并且用户将为该类方法提供用户定义的枚举,其特定类型对于正在设计的类是未知的-我们将此类称为“库类”)。

我想在语法上尽可能地限制该参数类型,以便只允许使用正确的类型。

我的要求是,该类型必须是实现特定接口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.classt = 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 ? ;
            }
        }

    }

    //...

我应该如何完成该代码?

是的,这是安全的,因为Number[]Integer[]的超类(与List<Number> 并非 List<Integer>的超类相反)。

因此,如果所宣称的组件类型tt (声明的类型的元件中的tt )实现EnumKind ,这种元件的阵列延伸EnumKind[]因此,这是安全的:

EnumKind[] tt = (EnumKind[]) t.getEnumConstants(); // Casting to superclass: OK

您不会收到任何警告,因为这是安全的,并且永远不会收到ClassCastException

要使用.getText T也必须“扩展” EnumKind。 枚举包装器不提供此功能。

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('_', ' ') + "#";
}

通用方法如何:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM