泛型(generic type):声明中具有一个或者多个类型参数的类或者接口的统称。
原始类型(raw type):没有任何类型参数的泛型类型的名称。如List<E>对应的原生态类型是List。它们的存在主要是为了与没有泛型之前的代码相兼容。
出现泛型前:
// Now a raw collection type - don't do this!
//这个集合里面应该放stamp类的实例
private final Collection stamps = ...;
//如果把Coin类的实例放进去了,编译和运行照常进行
stamps.add(new Coin());
//直到从stamps集合中获取将coin取出来,却误以为它是stamp才会出错
for(Iterator i = stamps.iterator(); i.hasNext(); ) {
Stamp s = (Stamp) i.next();
}
有了泛型之后:
private final Collection<Stamp> s = ...;
//编译的时候,这句代码就会出错
s.add(new Coin());
List和List<Object>的区别:前者逃避泛型检查,后者明确告诉编译器,它能持有任意类型的对象。虽然可以将List<String>传递给类型List的参数,但不能传递给类型List<Object>的参数。因为List<String>不是List<Object>的子类型。
无限制通配类型Set<?>和Set的区别:如果不确定或者不关心实际的类型参数,就使用无限制通配类型,不能将任何元素(除null外)放到Set<?>中,如果尝试这样做,在编译时就会提示错误。
不要在新代码中使用原生态类型,除非两个例外【两者都源于泛型信息可以在运行时被擦除(JVM不知道泛型系统的存在)】:
1、在类文字中必须使用原生类型。规范不允许使用参数化类型(虽然允许数组类型和基本类型)。换句话说,List.class,String[].class,int.class都是允许的,但就List<String>.class和List<?>.class则不合法。
2、由于泛型信息可以在运行时被擦除,因此在参数化类型而非无限制通配符上使用instanceof操作是非法的。用无限制通配符类型代替原生态类型,对instanceof操作符的行为又不会产生任何影响(因为?代表的任意一种类型,但是是确定的)。这种情况下使用原生类型做成了首选,下面是利用泛型来使用instanceof操作符的首选方法:
// Legitimate use of type - instanceof operator
if (o instanceof Set) { // Raw type
Set<?> m = (Set<?>) o; // Wildcard type
}
上面的代码做了什么?首先确定了o是一种Set,但是是哪一种并不知道,这样直接将其转换成无限制通配符类型Set<?>,这是受检的转换,不会导致编译时警告。
总结:
总之,使用原始类型可能导致运行时异常,所以不要使用它们
记住以下三种情况的区别:
1、Set<Object>是个参数化类型,表示可以包含任何对象类型的一个集合。
2、Set<?>是一个通配符类型,表示只能包含某种未知对象类型的一个集合。
3、Set是一个原生态类型,它脱离了泛型系统。前两种是安全的,最后一种是不安全的。
为了快速参考,下表中总结了本条目(以及本章稍后介绍的一些)中介绍的术语:
术语 | 中文含义 | 举例 | 所在条目 |
---|---|---|---|
Parameterized type | 参数化类型 | List<String> | 条目 26 |
Actual type parameter | 实际类型参数 | String | 条目 26 |
Generic type | 泛型类型 | List<E> | 条目 26 |
Formal type parameter | 形式类型参数 | E | 条目 26 |
Unbounded wildcard type | 无限制通配符类型 | List<?> | 条目 26 |
Raw type | 原始类型 | List | 条目 26 |
Bounded type parameter | 限制类型参数 | <E extends Number> | 条目 29 |
Recursive type bound | 递归类型限制 | <T extends Comparable<T>> | 条目 30 |
Bounded wildcard type | 限制通配符类型 | List<? extends Number> | 条目 31 |
Generic method | 泛型方法 | static <E> List<E> asList(E[] a) | 条目 30 |
Type token | 类型令牌 | String.class | 条目 33 |