第23条:请不要在新代码中使用原生态类型

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 Collection<Stamp> s = ...;

//编译的时候,这句代码就会出错
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<?>。

原文地址:https://www.cnblogs.com/13jhzeng/p/5717827.html