【问题标题】:Simplest way to cast a Class<T> to a Class<E extends Enum<E>> without losing type information将 Class<T> 转换为 Class<E extends Enum<E>> 而不丢失类型信息的最简单方法
【发布时间】:2014-03-14 13:18:23
【问题描述】:

我有一个方法createFoo(),它使用Class&lt;T&gt; 实例为T 创建Foo&lt;T&gt; 的实例。现在我想扩展该方法以将使用枚举类型进行的调用转发到方法createEnumFoo()。从第一种方法调用第二种方法似乎并不简单。下面是一个示例,说明我如何使用两个未经检查的强制转换和一个额外的方法来做到这一点,我想摆脱所有这些。

方法castEnumType() 是必需的,因为我找不到将Class&lt;?&gt; 转换为Class&lt;E extends Enum&lt;E&gt;&gt; 的方法,而无需在某处绑定E。这涉及未经检查的演员表,因为我还没有找到使用Class.asSubclass() 的方法。创建Foo 的实例后,我需要将其从Foo&lt;E&gt; 转换为Foo&lt;T&gt; 事件,尽管ET 将始终是相同的类型。

我不能削弱createEnumFoo() 的签名,因为它正在调用Enum.valueOf(enumType, ...),并且要求其结果为E 类型。

final class Example {
    <E extends Enum<E>> Foo<E> createEnumFoo(Class<E> enumType) {
        // This makes use of e.g. Enum.valueOf(enumType, ...).
        return null;
    }

    <E extends Enum<E>> Class<E> castEnumType(Class<?> enumType) {
        return (Class<E>) enumType;
    }

    <T> Foo<T> createFoo(Class<T> type) {
        if (Enum.class.isAssignableFrom(type))
            return (Foo<T>) createEnumFoo(castEnumType(type));
        else
            // Here we would do something else or maybe throw an exception.
            return null;
    }

    interface Foo<T> {
    }
}

有没有更简单的方法来做到这一点?


一些上下文

为了澄清我面临的问题,我将解释这个问题是如何在我正在从事的项目中实际出现的:

在我遇到这个问题的代码中,Foo&lt;T&gt; 实际上是Converter&lt;T&gt;,它是一个允许T 的实例在JSON 值:

public interface Converter<T> {
    JsonObject encode(T value);

    T decode(JsonObject data);
} 

createFoo() 实际上是一个方法converterForType(),它采用Class&lt;T&gt; 实例并动态分派到一组静态方法和字段,这些静态方法和字段为常见的Java 类型和特定于项目的类型创建/包含转换器。通常当需要转换器时,直接访问适当的方法/字段,但有些地方只有在运行时才知道类型,这就是使用converterForType()的地方。

现在我想扩展该方法以通过将枚举类型转换为包含枚举常量名称的 JSON 字符串来自动处理枚举类型。这就是为什么我需要从converterForType() 调用方法enumConverter()。这是enumConverter()的实现:

public static <E extends Enum<E>> Converter<E> enumConverter(final Class<E> enumClass) {
    return new Converter<E>() {
        public JsonObject encode(E value) {
            return Json.convert(value.name());
        }

        public E decode(JsonObject data) {
            return Enum.valueOf(enumClass, data.asString());
        }
    };
}

【问题讨论】:

  • 我不确定有没有更好的方法。请参阅此相关帖子:Passing a runtime resolved parameter to a method which has multiple bound type, compilation error。但是,您实际上是如何返回枚举实例的?视情况而定,您可以只使用Class.getEnumConstants()。让我知道我是否应该用答案对此进行扩展。
  • 你能展示一个使用 Enum 类创建Foo 的例子吗?
  • @PaulBellora @Radiodef 我添加了一个关于这个问题在项目中实际出现的位置的描述。如果我直接调用enumConverter(),从给定的Class&lt;E&gt; 实例访问枚举常量不是问题。

标签: java generics casting enums


【解决方案1】:

这样呢,对 createEnumFoo 方法使用原始类型
编辑:修复了 @Feuermurmel 在 cmets 中报告的编译错误

@SuppressWarnings({ "unchecked", "rawtypes" })
final class Example
{
    <E extends Enum<E>> Foo<E> createEnumFoo(Class enumType)
    {
        // This makes use of e.g. Enum.valueOf(enumType, ...).
        Enum x = Enum.valueOf(enumType, "x");
        return (Foo<E>) x;
    }

    <T extends Enum> Foo<T> createFoo(Class<T> type)
    {
        if (Enum.class.isAssignableFrom(type))
            return (Foo<T>) createEnumFoo(type);
        else
            // Here we would do something else or maybe throw an exception.
            return null;
    }

    interface Foo<T>
    {
    }
}

【讨论】:

  • 其实你是对的。如果我不能避免未经检查的强制转换,我可能也可以使用原始类型。但是我改为在createEnumFoo() 的调用站点向Class 添加了一个演员表,而不是削弱该方法的签名:return (Foo&lt;T&gt;) createEnumFoo((Class) type);。顺便说一句:createEnumFoo() 不能返回 Enum&lt;?&gt;,就像您在代码中所做的那样,它需要返回一些 Foo&lt;E&gt;。你能解决这个问题吗?
  • 我的代码在 eclipse (java 7) 中正确编译。 &lt;E extends Enum&lt;E&gt;&gt; Foo&lt;E&gt; createEnumFoo(Class enumType) { // This makes use of e.g. Enum.valueOf(enumType, ...). Foo&lt;E&gt; foo =Enum.valueOf(enumType, "x"); return foo; }
  • 当我将答案中的代码复制并粘贴到名为Example.java 的文件中并运行javac Example.java 时,它会打印以下错误:Example.java:7: error:incompatible types。见这里:ideone.com/zaYv7B
  • 我知道已经赌了四年,但我修复了编译错误:)
猜你喜欢
  • 1970-01-01
  • 2015-06-14
  • 2021-08-31
  • 1970-01-01
  • 2012-05-07
  • 1970-01-01
  • 1970-01-01
  • 2021-01-17
  • 2017-11-13
相关资源
最近更新 更多