注意:这个问题更多的是关于泛型而不是关于枚举。
我有很少的枚举类型,都实现了一个通用接口IEffect
。
例如
enum ElementalEffect implements IEffect {
FIRE, WATER;
}
enum CombatEffect implements IEffect {
PARALYSIS, SLEEP;
}
我想解析一个配置文件,它应该为武器添加效果。为此,我必须将一个给定的名称解析为其中一个效果。为了保持简单,我想写一个像这样的方法(主要是伪代码,这不会编译。实际上问题的关键是如何进行编译):
IEffect resolveEffectName(String name, Class... clazzes) {
for(Class clazz : clazzes) {
try {
return Enum.valueOf(clazz, name);
} catch(IllegalArgumentException) { /* ignore, try next class */}
}
throw new IllegalArgumentException("No matching effect found for " + name);
}
// resolveEffectName(readNameFromFile, ElementalEffect.class, CombatEffect.class);
现在我遇到的问题是,如果没有编译器告诉我
,我无法弄清楚如何编写该方法Enum类型中的方法
valueOf(Class<T>, String)
不适用于参数...
人们说它应该是
private static ICombatEffectType getFirstResolved(String name, Class<? extends Enum<?>>... classes) {
for (Class<? extends Enum<?>> clazz : classes) {
try {
return Enum.valueOf(clazz, name);
} catch (IllegalArgumentException e) {
}
}
return null;
}
这不起作用。随意尝试(如果你不相信我)。
Enum类型中的方法
valueOf(Class<T>, String)
不适用于参数(Class<capture#6-of ? extends Enum<?>>, String)
答案 0 :(得分:2)
如果这是你的风格,你可以流利地写这个:
class FluentGetter {
private final String name;
private IEffect found;
FluentGetter(String name) { this.name = name; }
<T extends Enum<T> & IEffect> FluentGetter search(Class<T> clazz) {
if (found == null) { // If you've already found something, don't overwrite that.
try {
found = Enum.valueOf(clazz, name);
} catch (IllegalArgumentException e) {}
}
return this;
}
IEffect get() {
return found; // + check if it's null, if you want.
}
}
然后:
IEffect effect =
new FluentGetter(name)
.search(ElementalEffect.class)
.search(CombatEffect.class)
.get();
通过为每个类分别进行方法调用,避免了类数组的泛型边界问题。
很确定我不会自己使用它;只是把它作为一种选择扔掉。
答案 1 :(得分:1)
你真正想要的是枚举常量的名称映射,你可以使用流轻松制作:
{{1}}
答案 2 :(得分:1)
我找到了一种方法,可以使用包装类使所有内容无需警告:
private static class Wrapper<T extends Enum<T> & IEffect> {
private Class<T> clazz;
public Wrapper(Class<T> clazz) {
this.clazz = clazz;
}
public IEffect resolveName(String name) {
return Enum.valueOf(clazz, name);
}
}
private static IEffect getFirstResolved(String name, Wrapper<?>... clazzes) {
for (Wrapper<?> clazz : clazzes) {
try {
return clazz.resolveName(name);
} catch (IllegalArgumentException e) {}
}
throw new IllegalArgumentException("No enum has a member " + name);
}
// Example call
ICombatEffectType elemental = getFirstResolved(
type,
new Wrapper<>(ElementalType.class),
new Wrapper<>(StatusEffect.class));
答案 3 :(得分:0)
这应该使用您的第一种方法编译(带警告):
private static final Map<String, IEffect> constants
= Stream.of(ElementalEffect.values(), CombatEffect.values())
.flatMap(Arrays::stream)
.collect(Collectors.toMap(Enum::name, Function.identity()));
IEffect resolveEffectName(String name) {
if(!constants.containsKey(name))
throw new IllegalArgumentException("No matching effect found for " + name);
return constants.get(name);
}