Java Enum.valueOf(Class<T> enumType, String name) 问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4014117/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 08:25:00  来源:igfitidea点击:

Enum.valueOf(Class<T> enumType, String name) question

javagenericsreflectionenums

提问by Tom

I am trying to get around a compile error ("Bound mismatch: ...") relating to dynamic enum lookup.

我正在尝试解决与动态枚举查找相关的编译错误(“绑定不匹配:...”)。

Basically I want to achieve something like this:

基本上我想实现这样的目标:

String enumName = whatever.getEnumName();
Class<? extends Enum<?>> enumClass = whatever.getEnumClass();
Enum<?> enumValue = Enum.valueOf(enumClass, enumName);

Whatever I do, I always end up with that compile error. Honestly, generics and enums are quite mindboggling to me...

无论我做什么,我总是以编译错误告终。老实说,泛型和枚举对我来说非常令人难以置信......

What am I doing wrong here?

我在这里做错了什么?

采纳答案by Sean Patrick Floyd

I think it won't work exactly like this unless you have access to a type variable (through either a type or method signature). The problem is the method signature of Enum.valueOf:

我认为除非您可以访问类型变量(通过类型或方法签名),否则它不会完全像这样工作。问题是方法签名Enum.valueOf

public static <T extends Enum<T>> T valueOf(
    Class<T> enumType,
    String name
);

There's no way to get a T without a type variable. But you can do it like this if you're willing to suppress some compiler warnings:

没有类型变量就无法获得 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());
}

Output:

输出:

ELVIS

猫王

回答by Tom Hawtin - tackline

The problem is with Class<? extends Enum<?>>. We want E extends Enum<E>, but we can't get that because we have two distinct wildcards.

问题在于Class<? extends Enum<?>>. 我们想要E extends Enum<E>,但我们无法得到它,因为我们有两个不同的通配符。

So we need to introduce a generic parameter, possible introduced by calling a method:

所以我们需要引入一个泛型参数,可能通过调用一个方法来引入:

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;
    }
}

But reflection is mucky and very rarely what you want. Don't do it.

但是反射是肮脏的,而且很少是你想要的。不要这样做。

回答by Sbodd

There's actually an alternate approach: you can use Class.getEnumConstantsand roll your own implementation of Enum.valueOfthat doesn't have the same type problems. The downside is you get back a generic Enum<?>- but if you knew what type you had coming in, you would be able to use Enum.valueOfanyway.

实际上有一种替代方法:您可以使用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);
}

(Note that my version returns nullif there's no such constant rather than throwing an IllegalArgumentException, but that's a trivial thing to change.

(请注意,null如果没有这样的常量而不是抛出,我的版本会返回IllegalArgumentException,但这是一个微不足道的改变。