動的な列挙型ルックアップに関連するコンパイルエラー(「バインドの不一致:...」)を回避しようとしています。
基本的に私はこのようなことを達成したいと思います:
String enumName = whatever.getEnumName();
Class<? extends Enum<?>> enumClass = whatever.getEnumClass();
Enum<?> enumValue = Enum.valueOf(enumClass, enumName);
私が何をするにせよ、私はいつもそのコンパイルエラーに終わります。正直なところ、ジェネリックスと列挙型は私にとってかなり困惑しています...
ここで何が悪いのですか?
(型またはメソッドのシグネチャのいずれかを介して)型変数にアクセスできない限り、これは正確に機能しないと思います。問題は、Enum.valueOf
のメソッドシグネチャです。
public static <T extends Enum<T>> T valueOf(
Class<T> enumType,
String name
);
型変数なしでTを取得する方法はありません。しかし、コンパイラの警告を抑制したい場合は、次のように実行できます。
public enum King{
ELVIS
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void main(final String[] args){
final Class<? extends Enum> enumType = King.class;
final Enum<?> theOneAndOnly = Enum.valueOf(enumType, "ELVIS");
System.out.println(theOneAndOnly.name());
}
出力:
エルビス
問題はClass<? extends Enum<?>>
にあります。 E extends Enum<E>
が必要ですが、2つの異なるワイルドカードがあるため、取得できません。
したがって、ジェネリックパラメーターを導入する必要があります。これは、メソッドを呼び出すことで導入できます。
enum MyEnum {
ME;
}
public class EnName {
public static void main(String[] args) {
Enum<?> value = of(MyEnum.class, "ME");
System.err.println(value);
}
private static <E extends Enum<E>> E of(Class<E> clazz, String name) {
E value = Enum.valueOf(clazz, name);
return value;
}
}
しかし、反射はごちゃごちゃしていて、ごくまれに望みのものです。しないでください。
実際には別のアプローチがあります。Class.getEnumConstants
を使用して、同じ型の問題がないEnum.valueOf
の独自の実装をロールできます。欠点は、一般的なEnum<?>
が返されることです。ただし、取得したタイプがわかっていれば、とにかくEnum.valueOf
を使用できます。
private static Enum<?> findEnumValue(Class<? extends Enum<?>> enumType, String value) {
return Arrays.stream(enumType.getEnumConstants())
.filter(e -> e.name().equals(value))
.findFirst()
.orElse(null);
}
(私のバージョンでは、null
をスローするのではなく、そのような定数がない場合はIllegalArgumentException
を返しますが、それは簡単な変更です。