如果在Java中将泛型类的实例声明为原始类型,编译器是否会为所有类成员方法假设参数化类型为Object
?这是否会延伸到那些返回某种形式(例如Collection
)具体参数化类型的方法?
我错误地声明了没有参数化类型的泛型类的实例,这导致了非常有趣的下游效果。我提供了一个简化的场景示例,该场景产生了“不兼容类型”编译错误。我的基本问题:为什么javac产生“不兼容类型”错误,抱怨下面的指示行?
import java.util.*;
public class Main {
public static void main(String[] args) {
final Test<String> t1 = new Test<String>();
final Test t2 = new Test<String>();
for (final Integer i : t1.getInts()) {
System.out.println(i);
}
for (final Integer i : t2.getInts()) { //<-- compile-time error
System.out.println(i);
}
}
public static class Test<T> {
public Test() {
}
public Set<Integer> getInts() {
final Set<Integer> outSet = new HashSet<Integer>();
outSet.add(new Integer(1));
outSet.add(new Integer(2));
outSet.add(new Integer(3));
return outSet;
}
}
}
一个有趣的说明是,如果使用通配符类型(t2
)声明Test<?> t2…
,则代码将按预期编译并运行。
for-each循环的使用在next()
返回的集合上的迭代器上调用getInts()
(它返回从迭代的Iterable中收集的泛型类型)。 The documentation here提到如果Iterable是raw,则Object
用作返回类型。为什么编译器似乎也将Test.getInts()
的返回类型从Set<Integer>
更改为Set<Object>
?
答案 0 :(得分:5)
由于您使用了原始Test
,因此Test
类中的所有泛型都是有效类型删除的,甚至是不相关的泛型,例如返回Set<Integer>
,因此Set<Integer>
getInts
返回的内容只是原始的Set
。这就解释了为什么你会得到不兼容的类型,因为原始Set
将返回Object
,而不是Integer
。
Section 4.8 of the JLS涵盖原始类型:
未从其超类或超接口继承的原始类型C的构造函数(第8.8节),实例方法(第8.4节,第9.4节)或非静态字段(第8.3节)M的类型是原始的在与C对应的泛型声明中对应于类型擦除的类型。
和
原始类型的使用仅允许作为遗留代码兼容性的让步。在将泛型引入Java编程语言之后编写的代码中使用原始类型是非常不鼓励的。未来版本的Java编程语言可能会禁止使用原始类型。
(强调我的)
这种行为的原因是为了向前兼容pre-generics Java代码,因为内置Java类的pre-generics版本与generified内置类的原始类型版本相同。也就是说,pre-generics Set
与原始Set
相同(删除了泛型)。
答案 1 :(得分:0)
是的,在将变量声明为原始类型时(或当表达式解析为原始类型引用时),与该引用的所有交互都会像删除所有泛型一样。这包括通用参数列表类型和返回类型。