第5章 泛型
26,请不要使用原生态类型
原生态类型:List,不带任何实际类型参数的的泛型名称
使用原生态类型是合法的,但是会失去泛型在安全性和描述性方面的所有方式。
List:不推荐,没有类型检查,
List < Object >:可行,明确告诉编译器,可以接受任何类型
List < String >:可行,可以传给List,但是不能传给 List
泛型有子类型化规则。
无限制通配类型:Set <?>,不确定或者不关心实际类型参数
Set 与 Set<?>
不能将任何元素(除了 null )放到 Collection<?> 中
泛型术语:
术语 | 范例 |
---|---|
原生态类型 | List |
泛型 | List < E > |
无限制通配符类型 | List<?> |
参数化的类型 | List < String > |
形式类型参数 | E |
实际类型参数 | String |
有限制参数类型 | < E extends Number > |
递归类型限制 | < T extends Comparable > |
有限制通配符类型 | List < ? extends Number > |
泛型方法 | static < E > List < E > asList (E [] a ) |
类型令牌 | String.class |
27,消除非受检警告
要尽可能消除每一个非受检异常
如果实在无法消除,但是可以证明代码是类型安全的,可以在任何粒度使用:
@SuppressWarning(unchecked)
但永远不要在类上使用!
将 SuppressWarning 放在 return 语句是不合法的
使用 SuppressWarning 时,要写明注释,说明为什么·这样子写时合法的
28,列表优于数组
创建泛型,参数化类型或者类型参数的数组是违法的。
new List < E > [ ]
new List < String > [ ]
new E [ ]
都是违法的
数组提供了运行时类型安全
列表提供了编译时类型安全
29,优先考虑泛型
两种消除泛型数组创建的方法:
1,数组被声明为E [ ] 类型清楚的表明它只含 E 实例,它只需要转换一次。
2,每次读取一个数组元素的时候就转换一次。
第一种方法优先,但是会导致堆污染。数组运行时类型有编译时类型不匹配。
30,优先考虑泛型方法
静态工具方法尤其适合泛型类
由于类型是通过擦除实现的,可以给所有必要的类型参数使用单个对象,但是需要编写一个静态工厂方法,让它可以重复地给每个必要的参数类型分发对象,这种模式称为单例模式。
递归类型限制
31,利用有限制通配符来提升API的灵活性
List < ? extends Number >
List < ? siper Number >
可以进行越级匹配
PECS:producer-extends,consumer-super
32,谨慎同时使用泛型和可变参数
可变参数是一个技术露底,调用一个可变参数时,会创建一个数组来存放可变参数
数组与泛型往往并不兼容,会产生堆污染。导致编辑器自动生成转换失败。
为什么显式创建泛型数组是非法(产生错误)的,但用泛型可变参数声明却是合法(产生警告)的呢?
带有泛型可变参数在实践中用处很大,在 Java 类库中:
Arrays.adList(T…a),Collections.addAll(Collertion<?> super T , T…elements,
以及EnumSet.of(E first , E… rest))。这些类库方法是安全的
解决方法:
1,@SuppressWarning(“unchecked”)
2,@SafeVarargs 对方法进行注解,这个注解是通过方法设计者做出承若,这个类是安全的。
从来不在不可变方法中保存任何值。
允许另一个方法访问一个泛型可变参数数组是不安全的。
33,优先考虑类型安全的异构容器
以类型安全的方式访问数据库所有的列:将键进行参数化,而不是将容器进行参数化。然后将键插入容器。
Favorites 类:是类型安全的。同时也是异构的。类型安全的异构容器,
当一个类的字面被用在方法中,来传达编译时和运行时的类型信息时,就被称作类型令牌。
favorites.getFavorites( )用到了 Class的cast( ) 方法,将对象引用动态地转换为了 Class 对象所表示的类型。
cast 方法就是 Java 的转化操作符动态模拟。
Favorites类有两个缺陷:
1,恶意客户端可以很轻松的破坏 Favorites 实例的类型安全。
2,不可以用在具体化的类型中。