这与 Java:使用反射实例化枚举类似,但不完全相同
我有一个 Map, FooHandler>
我想用它来映射 Enum
(我不关心哪种类型,或者即使它们是相同的类型,只要它们是枚举常量)到我的 FooHandler 类。
我想使用我读取的文本文件来填充此地图。我可以让它工作,但我有两个警告我想绕过:
static private <E extends Enum<E>> E getEnum(String enumFullName) {
// see https://stackoverflow.com/questions/4545937/
String[] x = enumFullName.split("\\.(?=[^\\.]+$)");
if (x.length == 2)
{
String enumClassName = x[0];
String enumName = x[1];
try {
Class<E> cl = (Class<E>)Class.forName(enumClassName);
// #1
return Enum.valueOf(cl, enumName);
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return null;
}
public void someMethod(String enumName, String fooHandlerName)
{
FooHandler fooHandler = getFooHandler(fooHandlerName);
Enum e = getEnum(enumName);
// #2
map.put(e, fooHandler);
}
警告#1:未经检查的强制转换
警告#2:Enum 是原始类型。
我得到#1,我想可以发出警告,但我似乎无法击败警告#2;我已经尝试过 Enum
这只是给了我一个关于泛型类型捕获绑定不匹配的错误。
更糟糕的替代实现:
在我的 >
通用返回值之前,我尝试返回 Enum 但没有成功;我收到这些警告/错误:
static private Enum<?> getEnum(String enumFullName) {
...
Class<?> cl = (Class<?>)Class.forName(enumClassName);
// 1
return Enum.valueOf(cl, enumName);
// 2
}
-
警告:
- 类型安全:来自 Class 的未经检查的强制转换到类
- 枚举是原始类型。对泛型类型 Enum 的引用应该参数化
- 枚举是原始类型。对泛型类型 Enum 的引用应该参数化
- 类中不必要的演员阵容到类
-
错误:
- 类型不匹配:无法从 capture#5-of 转换?到枚举
- 类型安全:泛型方法的未经检查的调用 valueOf(Class, String)
Enum 类型的 valueOf(Class, String)
- 绑定不匹配:Enum 类型的泛型方法 valueOf(Class, String)不是
适用于参数(Class, String)。推断类型 capture#5-of ?不是
有界参数 > 的有效替代
以及此:
static private Enum<?> getEnum(String enumFullName) {
...
Class<Enum<?>> cl = (Class<Enum<?>>)Class.forName(enumClassName);
// 1
return Enum.valueOf(cl, enumName);
// 2
- 警告:
类型安全:未检查来自 Class 的强制转换到 Class>
- 错误:
绑定不匹配:Enum 类型的泛型方法 valueOf(Class, String)不适用于参数(Class>、String)。推断类型 Enum不是有界参数 >
的有效替代
This is similar but not quite the same as Java: instantiating an enum using reflection
I have a Map<Enum<?>, FooHandler>
that I want to use to map Enum
s (I don't care which type or even if they are the same type, just as long as they are enum constants) to my FooHandler
class.
I would like to populate this map using a text file that I read. I can get it to work, but I have two warnings I would like to get around:
static private <E extends Enum<E>> E getEnum(String enumFullName) {
// see https://stackoverflow.com/questions/4545937/
String[] x = enumFullName.split("\\.(?=[^\\.]+$)");
if (x.length == 2)
{
String enumClassName = x[0];
String enumName = x[1];
try {
Class<E> cl = (Class<E>)Class.forName(enumClassName);
// #1
return Enum.valueOf(cl, enumName);
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return null;
}
public void someMethod(String enumName, String fooHandlerName)
{
FooHandler fooHandler = getFooHandler(fooHandlerName);
Enum e = getEnum(enumName);
// #2
map.put(e, fooHandler);
}
Warning #1: unchecked cast
Warning #2: Enum is a raw type.
I get #1 and could just put a warning I suppose, but I can't seem to beat warning #2; I've tried Enum<?>
and that just gives me an error about generic type capture bound mismatch.
Alternative implementations that are worse:
Before my <E extends Enum<E>>
generic return value, I tried returning Enum and it didn't work; I got these warnings/errors:
static private Enum<?> getEnum(String enumFullName) {
...
Class<?> cl = (Class<?>)Class.forName(enumClassName);
// 1
return Enum.valueOf(cl, enumName);
// 2
}
-
warnings:
- Type safety: Unchecked cast from Class<capture#3-of ?> to Class<Enum>
- Enum is a raw type. References to generic type Enum<E> should be parameterized
- Enum is a raw type. References to generic type Enum<E> should be parameterized
- Unnecessary cast from Class<capture#3-of ?> to Class<?>
-
errors:
- Type mismatch: cannot convert from capture#5-of ? to Enum<?>
- Type safety: Unchecked invocation valueOf(Class<Enum>, String) of the generic method
valueOf(Class<T>, String) of type Enum
- Bound mismatch: The generic method valueOf(Class<T>, String) of type Enum<E> is not
applicable for the arguments (Class<capture#5-of ?>, String). The inferred type capture#5-of ? is not
a valid substitute for the bounded parameter <T extends Enum<T>>
and this:
static private Enum<?> getEnum(String enumFullName) {
...
Class<Enum<?>> cl = (Class<Enum<?>>)Class.forName(enumClassName);
// 1
return Enum.valueOf(cl, enumName);
// 2
- warning:
Type safety: Unchecked cast from Class<capture#3-of ?> to Class<Enum<?>>
- error:
Bound mismatch: The generic method valueOf(Class<T>, String) of type Enum<E> is not applicable for the arguments (Class<Enum<?>>, String). The inferred type Enum<?> is not a valid substitute for the bounded parameter <T extends Enum<T>>
发布评论
评论(2)
对于#1,除了
SuppressWarnings("unchecked")
之外没有其他解决方案。对于 #2,声明存在问题:
您可以返回
E
,但编译器无法确定E
。没有E
或Class
类型的参数或任何允许它的参数。您可以编写它,但在某处会有未经检查的强制转换,当您调用它时,您可能会得到一个ClassCastException
。所以不要这样做。只需将其更改为即可,
因为这会起作用并且更公平。您会在每个调用站点上收到警告,这是正确的,因为有一些需要警告的内容。
For #1 there's no solution except
SuppressWarnings("unchecked")
.For #2 there's a problem with the declaration:
You can return
E
, but there's no way for the compiler to determineE
. There's no argument of typeE
orClass<E>
or whatever, which would allow it. You can write it, but there'll be an unchecked cast somewhere and when you call it, you may get aClassCastException
. So don't do it.Just change it into
as this will work and is more fair. You'll get a warning on each call site and that's correct as there is something to warn of.
签名
在这里对你没有任何好处。
>
允许方法的调用者将getEnum
的结果分配给他们想要的任何enum
类型没有任何转换:但是,这没有任何意义...如果调用者知道该方法将返回什么特定类型的
enum
,他们可以做一些更明智的事情,例如SomeEnum.valueOf (“某事”)
。这里唯一有意义的是
getEnum
仅返回Enum
,这似乎是您真正想做的事情:上面的编译没有警告并且工作正常。强制转换为
Class
警告被抑制,因为我们知道这样做并不安全,并且如果具有给定值的类,Enum.valueOf
将会爆炸。 name 不是一个enum
类,而这正是我们想要做的。The signature
isn't doing you any good here.
The
<E extends Enum<E>>
allows the caller of the method to assign the result ofgetEnum
to anyenum
type they want without any casting:However, that doesn't make any sense... if the caller knew what specific type of
enum
the method would return, they could do something more sensible likeSomeEnum.valueOf("SOMETHING")
.The only thing that makes sense here is for
getEnum
to just returnEnum<?>
, which seems like what you really want to do anyway:The above compiles with no warnings and works properly. The cast to
Class<Enum>
warning is suppressed because we know that it isn't safe to do that and thatEnum.valueOf
will blow up if the class with the given name isn't anenum
class and that's what we want to do.