Java 1.5发行版本增加了泛型。在没有泛型之前,从集合中读取到的每一个对象都必须进行显式转换,一旦插入了类型错误的对象,在运行时出错才被发现。有了泛型之后,就可以告诉编译器每个集合中接受哪些对象类型,编译器会自动进行转换,并在编译时告知是否插入类型错误的对象。
泛型指声明中具有一个或者多个类型参数的类或者接口。定义一组参数化的类型,构成格式为:类或者接口的名称,接着用尖括号<>把对应于泛型形式类型参数的实际类型参数列表括起来。例如List<String>,是一个参数化的类型,表示元素类型为String的列表,(String是与形式类型参数E相对应的实际类型参数)。
每个泛型都定义一个原生态类型,即不带任何实际类型参数的泛型名称,如List<E>对应的原生态类型是List。
在出现泛型之前,声明一个集合:
//这个集合里面应该放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 Collections = ...;//编译的时候,这句代码就会出错s.add(new Coin());
List和List<Object>的区别:前者逃避泛型检查,后者明确告诉编译器,它能持有任意类型的对象。虽然可以将List<String>传递给类型List的参数,但不能传递给类型List<Object>的参数。因为List<String>不是List<Object>的子类型。
无限制通配类型Set<?>和Set的区别:如果不确定或者不关心实际的类型参数,就使用无限制通配类型,不能将任何元素(除null外)放到Set<?>中,如果尝试这样做,在编译时就会提示错误。
必须使用原生态类型的例外:(源于泛型信息在运行时被擦除)
1.类文字,如List.class,String[].class 是合法的,List<String>,List<?>.class 是不合法的。
2.instanceof操作符
if (o instanceof Set) { Set m = Set o; ... }
红色标记的部分不需要使用Set<?>,这样显得多余。但是,一旦确定o是Set,就将它转换为Set<?>。