不要使用原始类型

不要使用原始类型

概述

首先,泛型类和接口都被成为泛型类型。每个泛型类都定义了一组参数化的类型,例如List<Strimg>就是一个参数化的类型。另外,每个泛型类型都定义了一个原始类型,即List<E>对应的原始类型是List,它的主要目的是为了兼容那些在泛型出现之前写的代码。

原始类型的问题

对于Java9,这样声明仍然是合法的:

1
2
3
4
5
6
7
// My stamp collection. Contains only Stamp instances.
private final Collection stamps = ... ;

for (Iterator i = stamps.iterator(); i.hasNext(); ) {
Stamp stamp = (Stamp) i.next(); // Throws ClassCastException
stamp.cancel();

并且如果你往集合里添加了一个其它的对象,仍然可以编译运行,最多是得到一个warning。在你尝试获取到Coin对象之前都不会出现错误。

使用了泛型方法后,编译器就知道集合只会包括Stamp实例这一点,插入不合法对象时,也会生成编译时错误:

1
private final Collection<Stamp> stamps = ... ;

你使用了原始类型,你将会失去泛型所带来的安全性和可读性。以原始类型List和参数化类型List<Object>之间的区别为例,前者不接受类型系统的检查,而后者则显示地告诉编译器它可以接受任意类型的对象。

如果使用参数化类型以允许插入任意对象,我们应该使用List<Object>;而对于元素类型未知而且不在乎元素类型的集合,更安全的方式是使用无限制通配符类型List<?>。无法将任意元素(null除外)放入一个Collection<?>。试图这么做的化将产生编译时错误。

例外

对于不能使用原始类型这个规则,有两个例外:一是在类字面值中使用原始类型,例如List.class, int.class;二是与instanceof有关,因为泛型类型信息在运行时是被擦除了的,所以在参数化类型而不是无限制通配符类型上用instanceof操作符是非法的。