使用通配符 Class<?> 从 Class 个枚举中检索枚举

Use Wildcard Class<?> to retrieve Enum from Class of Enums

我有以下代码

public interface SomeInterface {    }


public class TestConstants {
    public static <E extends Enum<E> & SomeInterface> E getEnumString(Class<E> clazz, String s){
        for(E en : EnumSet.allOf(clazz)){
            if(en.name().equalsIgnoreCase(s)){
                return en;
            }
        }
        return null;
    }
    public enum A implements SomeInterface {
        V1,
        V2,
        V3;
    }

    public enum B implements SomeInterface {
        V1,
        V2,
        V3;
    }
    // And so on.......
}

我可以在代码的其他地方调用 call

TestConstants.getEnumString(TestConstants.B.Class,"V2")

它会 return TestConstants.B.V2 一切都很好。

但我的问题是,如果我不知道实际的枚举怎么办 class 我会搜索 即

Class<?> enumClass 包含其中一个枚举,但我不知道是哪个。 现在我从 TestConstants class 外部的代码,我可以使用类似下面的代码

if (enumClass.equals(TestConstants.A.class)) {
    TestConstants.getEnumString(TestConstants.A.class,value);
} else if (enumClass.equals(TestConstants.B.class)) {
    TestConstants.getEnumString(TestConstants.B.class,value);
} else if (enumClass.equals(TestConstants.C.class)) {
// And so on....

但我真的很想将这段代码移到 TestConstants class 中。但我似乎做不到。 例如,如果我添加此功能

public static <E extends Enum<E> & SomeInterface> E fromUnknownClass(Class<?> enumClass, String name) {
    if (enumClass.equals(TestConstants.A.class)) {
       return TestConstants.fromString(TestConstants.A.class,name); <-- Compile error
    } else if .......
        .......
}

我得到以下编译错误

incompatible types: inference variable E has incompatible bounds equality constraints: 
TestConstants.A upper bounds: E,java.lang.Enum<E>,SomeInterface

我在这里尝试的是否可行,或者是否有一些我不知道的泛型魔法?

你让你的生活变得不必要的艰难。在你的通用签名中

public static <E extends Enum<E> & SomeInterface> E getEnumString(Class<E> clazz, String s)

SomeInterface 的声明已过时。毕竟,无论特定 enum 是否实现 SomeInterface,该方法都有效。它保证返回的类型与您传入的 class 匹配(读取:属于 E 类型)因此结果将实现 SomeInterface if E 实施 SomeInterface.

因此,如果您将方法更改为

public static <E extends Enum<E>> E getEnumString(Class<E> clazz, String s)

并传入 A.classB.class 结果将分别为 AB 类型,两者都实现 SomeInterface。这甚至适用于调用者可能确实需要实现 SomeInterface 约束的通用上下文:

public <T extends Enum<T>&SomeInterface> void doSomethingWithSomeInterface(Class<T> cl) {
    // works without getEnumString declaring SomeInterface ...
    T t=getEnumString(cl, "V1");
}

但是,如果你传入一个Class<?>,没有人能说结果是否会实现SomeInterface,最好的验证方法是进行普通转换或instanceof关于结果。

如果您按上述方式更改了签名,即使是未知类型也很容易使用:

Class<?> cl=A.class; // the "unknown" type Class<?>
Object obj=getEnumString(cl.asSubclass(Enum.class), "V1");

请注意,如果您不需要不区分大小写的匹配,有更简单的方法来获取 enum 常量。对于已知类型,您可以简单地调用,例如A.valueOf("V1"),而对于泛型方法,它很简单:

public static <E extends Enum<E>> E getEnumString(Class<E> clazz, String s){
    return Enum.valueOf(clazz, s);
}

这使得整个实用程序方法已过时,因为 Enum.valueOf(Class, String) 已经 该实用程序方法。

即使您需要不区分大小写的查找,您可能会认为 enum 常量通常全部大写,如果您遵守此约定,整个操作将变为:

Class<?> clazz=A.class; // simulate unknow type
String name="v1"; // for case insensitive match
// the operation:
Object aV1=Enum.valueOf(clazz.asSubclass(Enum.class), name.toUpperCase(Locale.ROOT));
SomeInterface si=(SomeInterface)aV1;

不需要额外的实用方法。