【问题标题】:Use Wildcard Class<?> to retrieve Enum from Class of Enums使用通配符 Class<?> 从枚举类中检索枚举
【发布时间】:2015-02-27 00:15:02
【问题描述】:

我有以下代码

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

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

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

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

但我的问题是,如果我不知道我将搜索的实际 Enum 类怎么办 即

Class&lt;?&gt; enumClass 包含其中一个枚举,但我不知道是哪个。 现在我使用 TestConstants 类外部的代码,我可以使用类似以下的代码

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 类中。但我似乎无法做到。 例如,如果我添加此功能

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

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

【问题讨论】:

  • 您返回 e.name()...枚举的字符串表示形式...您不想要枚举吗?或者,您将“v2”放入参数中有什么意义,只是为了取回“v2”......?
  • 我不明白你的问题。因此,在“TestConstants 外部的代码”中更好或更简单地解释它,您只需调用 TestConstants.getEnumString(enumClass,value);您不必“静态地”提供类名
  • 您是否尝试将Class&lt;?&gt; 参数转换为Class&lt;E extends Enum&lt;E&gt; &amp; SomeInterface&gt;
  • 也许这就是你需要的? stackoverflow.com/q/15978730/2001247
  • @ElDuderino 发布了具有您需要的答案的问题。你必须提出论点。但请注意答案中的警告。

标签: java generics enums java-8


【解决方案1】:

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

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

SomeInterface 的声明已过时。毕竟,无论特定的enum 是否实现SomeInterface,该方法都有效。它保证返回的类型与您传入的类匹配(阅读:类型为E)因此结果将实现SomeInterface 如果 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&lt;?&gt;,没有人能说结果是否会实现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;

无需额外的实用方法。

【讨论】:

    猜你喜欢
    • 2010-12-10
    • 2011-10-09
    • 1970-01-01
    • 1970-01-01
    • 2019-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多