2

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

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?我需要Bar<Foo<?>>,而不是Bar<Foo>,因为有只接受Bar<Foo<?>>作为参数的方法。欣赏想法。

4

3 回答 3

3

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

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

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

双重转换是必要的,因为编译器知道 Foo.class 与 Class> 不兼容,因此您必须首先将其转换为“原始”类型 Class:在表达式中使用原始类型会禁用编译器的泛型类型检查那个表达,那么“不可能”的演员阵容就可以了。

于 2015-11-12T21:28:50.170 回答
1

<>如您的问题帖子中所示,您不能在不提供类型信息的情况下创建通用对象。您必须提供类型或使用原始版本。如果你被迫使用通配符参数类型,那么只需使用原始类型抑制警告,如下所示

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

//Bar is having no type "<>" (but this is not recommended
于 2015-11-12T21:32:28.430 回答
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>在构造函数中强制转换它是安全的。

于 2015-11-12T23:12:31.047 回答