How do I get the value of an Enum, if I don't know the class at compile time?
I'm trying to do the following:
Class<?> cls = unknownClass;
if(cls.isEnum()){
@SuppressWarnings("unchecked")
Class<? extends Enum<?>> en开发者_开发百科umClass = (Class<? extends Enum<?>>) cls;
Object val = Enum.valueOf(enumClass, "NAME1");
}
But I get the following error:
Bound mismatch: The generic method valueOf(Class<T>, String) of type Enum<E> is
not applicable for the arguments (Class<capture#5-of ? extends Enum<?>>, String).
The inferred type capture#5-of ? extends Enum<?> is not a valid substitute for
the bounded parameter <T extends Enum<T>>
Can someone tell me what I am doing wrong?
Given that the cast won't really be checking things, I'd go with the completely raw version:
if (cls.isEnum()){
@SuppressWarnings("unchecked")
Object val = Enum.valueOf(cls, "NAME1");
}
That seems to work. Complete example:
public class Test
{
enum Foo
{
BAR, BAZ
}
public static void main(String[] args)
{
@SuppressWarnings("rawtypes")
Class cls = Foo.class;
if (cls.isEnum())
{
@SuppressWarnings("unchecked")
Object value = Enum.valueOf(cls, "BAR");
System.out.println(value);
}
}
}
The problem is that you have two ?
and they could be different and they have to be the same.
You either have to use a non generic of declare a generic type like
public static <T extends Enum<T>> T val(Class<T> cls) {
if(cls.isEnum()) { // is redundant when the compiler checks this.
@SuppressWarnings("unchecked")
Class<T> enumClass = (Class<T>) cls;
T val = Enum.valueOf(enumClass, "NAME1");
return val;
}
return null;
}
However, calling this method is a bit of a nightmare as well. ;)
Class.getEnumConstants
will give all the enums, which you can then find the one you are interested in.
Modifying Jon's code:
public class Test {
private enum Foo {
BAR, BAZ
}
public static void main(String[] args) {
Class<?> cls = Foo.class;
if (cls.isEnum()) {
for (Object constant : cls.getEnumConstants()) {
Enum<?> enumConstant = (Enum<?>)constant;
if (enumConstant.name().equals("BAR")) {
System.out.println(constant);
break;
}
}
}
}
}
In Java SE 8, you'll possibly be able do something clever with a lambda and abstracted control flow.
Note:
- Reflection is almost always a really bad idea.
- No need for unchecked warning or suppression of those valid warnings.
- No need for rawtypes (which ever spelling and semantics) warning or suppression of those valid warnings.
- No need for an unfounded rant.
- No need to downvote this answer.
Using raw type is good. While Java was reluctant to add raw type, it has been proven to be necessary and indispensable, beyond backward compatibility issues.
Without raw types, to solve your problem in a theoretically perfect way, Java has to be way more complicated. It probably needs a type-variable-variable. At that point, the code is no longer to please the humans, it is to please the machines. (We are probably already at this point, considering all the generics code that are impossible to understand)
class EnumValues<P extends Enum<P>>
{
public static <P extends Enum<P>> P [] getValues( Class<P> keyType)
{
return keyType.getEnumConstants();
}
}
Usage:
Class cls = Thread.State.class;
for( Enum en : EnumValues.getValues( cls))
System.out.println( en.name());
精彩评论