Java1.5中添加了泛型。没有泛型之前,从集合中读取的每一个对象都必须进行转换,如果不小心添加了类型错误的对象,在运行时的转换处理就会出错。有了泛型之后,子啊编译时就会告知是否插入了错误的类型
第23条 请不要在代码中使用原生态类型
每个泛型都定义一个原生态类型(raw type),即不带任何实际类型参数的泛型名称。例如,与List<E>相对呀的原生态类型是List。
java为了兼容性,开发者仍然可以使用原生态类型,但这样就失去了泛型在安全性和表达性方面的所有优势。
如果要使用泛型,但不确定或者不关心实际的类型参数,就可以使用一个问好代替。泛型Set<E>的无限制通配符类型为Set<?>,这是最普通的参数化Set类型,可以持有任何集合。但是不能把除了null以外的任何月严肃放到Collection<?>中,不然编译器会报错。
第24条:消除非受检警告
当遇到非受检警告时。如果消除了所有警告,就可以确代码是类型安全的,是一件很好的事情。这意味着不会子啊运行时出现ClassCastException一场,你会更加自信自己的程序可以实现预期的功能。
如果无法消除警告,同时可以证明引起警告的嗲吗是类型安全的,(只有这种情况下才)可以用一个@SuppressWarnings("unchecked")注解来禁止这条警告。
永远不要在整个类上使用SuppressWarnings,这样做可能会掩盖了重要的警告。
总的来说,要尽量减小SuppressWarnings的作用范围。并用注释把禁止该警告的原因记录下来。
第25条:列表优先于数组
创建泛型数组是非法的。
数组是协变可以具体化的,泛型是不可变且可以被擦除的。因此,数组提供了运行时的类型安全,但是没有编译时的类型安全,反之,对于泛型也一样。
数组的协变性(covariant)是指:
如果类Base是类Sub的基类,那么Base[]就是Sub[]的基类。
而泛型是不可变的(invariant),List<Base>不会是List<Sub>的基类,更不会是它的子类。
数组是在运行时才去判断数组元素的类型约束,而泛型正好相反,在运行时,泛型的类型信息是会被擦除的,只有编译的时候才会对类型进行强化。
java泛型是编译器泛型,是一种语法糖,生成的二进制代码中是没有泛型的,jvm感受不到泛型。java的泛型编译生成二进制代码的时候,进行了类型的擦除,放入集合的实际上是object类型,从集合中获取对象的时候 获取的是object类型, 然后进行了强制类型转换,转换成实际的类型。
第26条:优先考虑泛型
这条主要介绍了如何写泛型
使用泛型类比使用需要在客户端类中转换的类型要安全的多。也更加容易。在设计新类型的时候,要确保它们不需要转换就可以使用,这通常意味着要把类做成是泛型的。只要时间允许,就把所有的类泛型化。这对于这些类型的新用户来说会变得更加轻松,又不会破坏现有的客户端。
第27条:优先考虑泛型方法
泛型构造器必须指定参数类型,而泛型方法不需要。
泛型构造器指定参数类型的时候比较麻烦,所以推荐用静态工厂类代替构造器
第28条:利用有限制通配符来提升API的灵活性
第29条:优先考虑类型安全的异构容器
类Class在Java 1.5版本中被泛型话了。类的类型从字面上来看不再只是简单的Class,而是Class<T>.
//类型安全的异构兼容类型--API
public class Favorites {
public <T> void putFavorites(Class<T> type, T instance);
public <T> getFavorite(Class<T> type);
}
//类型安全的异构兼容类型--client
public static void main(String[] args) {
Favorites f = new Favorites();
f.putFavorite(String.class, "Java");
f.putFavorite(Integer.class, 0xcafebabe);
f.puFavorite(Class.class, Favorites.class);
String favoriteString = f.getFavorite(String.class);
int favoriteInteger = f.getFavorite(Integer.Class);
Class<?> favoriteClass = f.getFavorite(Class.class);
System.out.printf("%s %x %s%n",favoriteString, favoriteInteger, favoriteClass);
}
打印出来的结果是Java cafebabe Favorites.
Class的cast方法是Java的cast操作符的动态模拟。它只检验它的参数是否为Class对象所表示的类型的实例。如果是,就返回参数;否则就抛出ClassCastException异常。