【问题标题】:Java type inference with erasure带擦除的 Java 类型推断
【发布时间】:2016-02-14 09:07:18
【问题描述】:

在擦除和类型推断方面存在一些问题。我有以下类层次结构,看起来不是很复杂:

public class Foo<T> {

}

public class Bar<T> {
    private final Class<T> clazz;

    public Bar(Class<T> clazz) {
        this.clazz = clazz;
    }
}

而我正在尝试做的是这样的事情:

Bar<Foo<?>> bar = new Bar<>(Foo.class);

当然,这不起作用,因为 Foo 不完全是 Foo&lt;?&gt;。问题是如何构建这样的 Bar?我需要的正是Bar&lt;Foo&lt;?&gt;&gt;,而不是Bar&lt;Foo&gt;,因为有一种方法只接受Bar&lt;Foo&lt;?&gt;&gt; 作为参数。欣赏想法。

【问题讨论】:

  • 您可以将Foo.class 转换为Class&lt;Foo&lt;?&gt;&gt;,这可能足以满足您的目的。 (您不能实际上仅使用 Class 对象来表示不同的泛型。)

标签: java generics type-inference erasure


【解决方案1】:

抱歉,没有这样的Class 对象,因为正如您所注意到的,擦除意味着不存在。你需要投射它:

((Class<Foo<?>>)(Class)Foo.class)

这将为您提供所需的范围,但可能会生成编译器警告,因为您正在执行未经检查的泛型转换。这是合理的:编译器要求您承认您正在抛弃泛型的编译时安全性。但是在这种情况下,这种情况确实不可能在您的程序中或将来产生运行时错误,所以没关系。

双重转换是必要的,因为编译器知道 Foo.class 与 Class> 不兼容,所以你必须首先将它转换为“原始”类型 Class:在表达式中使用原始类型会禁用编译器的泛型-对该表达式进行类型检查,因此“不可能”转换可以正常工作。

【讨论】:

    【解决方案2】:

    如果不提供 &lt;&gt; 中的类型信息,您将无法创建通用对象,如您的问题帖子中所示。您必须提供类型或使用 raw 版本。如果强制使用通配符参数类型,那么只需使用原始类型抑制警告,如下所示

    @SuppressWarnings("rawtypes")
    Bar<Foo<?>> bar = new Bar(Foo.class);       
    
    //Bar is having no type "<>" (but this is not recommended
    

    【讨论】:

    • 没错,我最初没有明白你的回答的重点。这与更复杂的建议一样正确。
    • 我认为这是一个选项。想知道为什么我自己不尝试 :) 谢谢!
    【解决方案3】:

    由于 java.lang.Class 是不可变的,您可以在 Bar 的构造函数中使用较弱的类型声明:

    class Foo<T> {}
    
    class Bar<T> {
        private final Class<? extends T> clazz;
    
        public Bar(Class<? extends T> clazz) {
            this.clazz = clazz;
        }
    }
    

    如果您仍然需要该字段的类型为 Class&lt;T&gt; 而不是 Class&lt;? extends T&gt;,则在构造函数中强制转换它是安全的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-17
      • 1970-01-01
      相关资源
      最近更新 更多