具有擦除的Java类型推断

时间:2015-11-12 21:24:11

标签: java generics type-inference erasure

有一些擦除问题&类型推断。我有以下类层次结构,它看起来并不复杂:

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<?>。问题是如何建造这样一个酒吧?我需要完全Bar<Foo<?>>,而不是Bar<Foo>,因为有一种方法只接受Bar<Foo<?>>作为参数。欣赏想法。

3 个答案:

答案 0 :(得分:3)

抱歉,没有这样的Class对象,因为正如您所说,擦除意味着无法进行。你需要施展它:

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

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

双重转换是必要的,因为编译器知道Foo.class与Class&gt;不兼容,所以你必须先将它转换为“raw”类型Class:在表达式中使用原始类型会禁用编译器的泛型 - 对这个表达式进行类型检查,这样“不可能”的演员阵容就可以了。

答案 1 :(得分:1)

如果不在<>中提供类型信息,则无法创建通用对象,如问题帖子所示。您必须提供类型或使用原始版本。如果您被迫使用通配符参数类型,则只需使用原始类型来禁止警告,如下所示

@SuppressWarnings("rawtypes")
Bar<Foo<?>> bar = new Bar(Foo.class);       

//Bar is having no type "<>" (but this is not recommended

答案 2 :(得分:0)

由于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<T>而不是Class<? extends T>,则可以在构造函数中将其强制转换。