如果您在 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 是原始的,Object
用作返回类型。为什么编译器似乎也更改了 Test.getInts()
的返回类型来自 Set<Integer>
至 Set<Object>
?
最佳答案
因为你使用了原始的 Test
, Test
中的所有泛型类被有效地类型删除,甚至是不相关的泛型,如返回 Set<Integer>
,所以 Set<Integer>
由 getInts
返回变成原始的 Set
.这就解释了为什么你会得到不兼容的类型,因为原始的 Set
将返回 Object
s,不是 Integer
Section 4.8 of the JLS涵盖原始类型:
The type of a constructor (§8.8), instance method (§8.4, §9.4), or non-static field (§8.3) M of a raw type C that is not inherited from its superclasses or superinterfaces is the raw type that corresponds to the erasure of its type in the generic declaration corresponding to C.
和
The use of raw types is allowed only as a concession to compatibility of legacy code. The use of raw types in code written after the introduction of generics into the Java programming language is strongly discouraged. It is possible that future versions of the Java programming language will disallow the use of raw types.
(强调我的)
此行为的原因是为了与前泛型 Java 代码向后兼容,因为内置 Java 类的前泛型版本与泛型内置类的原始类型版本相同。也就是说,一个预泛型 Set
与原始 Set
相同(删除了泛型)。
关于Java - 泛型类的类成员的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23225728/