Java 带擦除的类型推断
Java type inference with erasure
擦除和类型推断有一些问题。我有以下 class 层次结构,看起来并不复杂:
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<?>>
作为参数。欣赏创意。
抱歉,不存在这样的 Class
对象,因为正如您所指出的,擦除意味着不可能存在。你需要施放它:
((Class<Foo<?>>)(Class)Foo.class)
这将为您提供所需的范围,但可能会生成编译器警告,因为您正在执行未经检查的通用转换。这是合理的:编译器要求您承认您正在抛弃泛型的编译时安全性。但是在这种情况下,这种情况真的不可能产生运行时错误,无论是在你的程序中还是在未来,所以没关系。
必须进行双重转换,因为编译器知道 Foo.class 与 Class> 不兼容,因此您必须先将其转换为 "raw" 类型 Class:在表达式中使用原始类型会禁用编译器对该表达式的泛型类型检查,因此 "impossible" 转换工作正常。
如您的问题 post 所示,您无法在 <>
中提供类型信息的情况下创建通用对象。您必须提供类型或使用 raw 版本。如果你被迫使用通配符类型,那么只需使用原始类型来抑制警告,如下所示
@SuppressWarnings("rawtypes")
Bar<Foo<?>> bar = new Bar(Foo.class);
//Bar is having no type "<>" (but this is not recommended
由于 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>
,则可以安全地将其转换为构造函数。
擦除和类型推断有一些问题。我有以下 class 层次结构,看起来并不复杂:
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<?>>
作为参数。欣赏创意。
抱歉,不存在这样的 Class
对象,因为正如您所指出的,擦除意味着不可能存在。你需要施放它:
((Class<Foo<?>>)(Class)Foo.class)
这将为您提供所需的范围,但可能会生成编译器警告,因为您正在执行未经检查的通用转换。这是合理的:编译器要求您承认您正在抛弃泛型的编译时安全性。但是在这种情况下,这种情况真的不可能产生运行时错误,无论是在你的程序中还是在未来,所以没关系。
必须进行双重转换,因为编译器知道 Foo.class 与 Class> 不兼容,因此您必须先将其转换为 "raw" 类型 Class:在表达式中使用原始类型会禁用编译器对该表达式的泛型类型检查,因此 "impossible" 转换工作正常。
如您的问题 post 所示,您无法在 <>
中提供类型信息的情况下创建通用对象。您必须提供类型或使用 raw 版本。如果你被迫使用通配符类型,那么只需使用原始类型来抑制警告,如下所示
@SuppressWarnings("rawtypes")
Bar<Foo<?>> bar = new Bar(Foo.class);
//Bar is having no type "<>" (but this is not recommended
由于 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>
,则可以安全地将其转换为构造函数。