Enum.valueOf(Class<T> enumType, String name) 问题
Posted
技术标签:
【中文标题】Enum.valueOf(Class<T> enumType, String name) 问题【英文标题】:Enum.valueOf(Class<T> enumType, String name) question 【发布时间】:2010-10-25 11:32:42 【问题描述】:我正在尝试解决与动态枚举查找相关的编译错误(“绑定不匹配:...”)。
基本上我想实现这样的目标:
String enumName = whatever.getEnumName();
Class<? extends Enum<?>> enumClass = whatever.getEnumClass();
Enum<?> enumValue = Enum.valueOf(enumClass, enumName);
无论我做什么,我总是以编译错误告终。老实说,泛型和枚举对我来说非常令人难以置信......
我在这里做错了什么?
【问题讨论】:
【参考方案1】:我认为除非您可以访问类型变量(通过类型或方法签名),否则它不会完全像这样工作。问题是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>
这样的“稀有类型”。
重点是 a) 如果没有辅助方法或类型,它就无法工作,b) 我们确信任何 Class<? extends Enum>
也将满足 Class<E extends Enum<E>>
(因为这就是 enum 的方式类工作)即使没有类型变量就无法检查。 @SuppressWarnings
是一个注释,只有当你知道自己在做什么时才应该使用,而且我知道。【参考方案2】:
问题在于Class<? extends Enum<?>>
。我们想要E extends Enum<E>
,但我们无法得到它,因为我们有两个不同的通配符。
所以我们需要引入一个泛型参数,可以通过调用方法引入:
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;
但是反射是肮脏的,很少是你想要的。不要这样做。
【讨论】:
感谢您的解释,它对进一步了解发生的事情有很大帮助。因为在我的特定用例中,我没有任何东西可以作为通用参数提供,所以我将寻求 seanizer 的答案。【参考方案3】:实际上还有另一种方法:您可以使用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
,但这是一件微不足道的改变。
【讨论】:
【参考方案4】:谢谢@Sbodd 的答案。我举了这个例子,添加了我们从标准 anEnum.valueOf("ELVIS") 中知道的异常,并以我们可以像这样使用它的方式更改了通用方法 args:
King king = findEnumValue(King.class, "ELVIS");
System.out.println(String.valueOf(king));
方法:
/**
* Returns the @link Enum for the given @link Enum#name() String of the given enum type.
* <p>
* Example:
* <pre>
* @code
King king = findEnumValue(King.class, "ELVIS");
System.out.println(String.valueOf(king));
*
* </pre>
* @param enumType the class of the enum, e.g. @code King.class.
*
* @param enumName the @link Enum#name(), e.g. "ELVIS".
*
* @return the enum instance or an exception.
*
* @throws IllegalArgumentException if the given @code enumName is no enum constant in the given @code enumType.
*/
public static <T extends Enum<T>> T findEnumValue(Class<T> enumType, String enumName) throws IllegalArgumentException
T result = Arrays.stream(enumType.getEnumConstants())
.filter(e -> e.name().equals(enumName))
.findFirst()
.orElse(null);
if(result == null)
throw new IllegalArgumentException(
"No enum constant " + enumType.getCanonicalName() + "." + enumName);
else
return result;
public enum King
ELVIS
【讨论】:
以上是关于Enum.valueOf(Class<T> enumType, String name) 问题的主要内容,如果未能解决你的问题,请参考以下文章