【effective java】23~29.泛型

23.请不要在新代码中使用原生态类型
a)简介
(1)泛型(generic):声明中具有一个或者多个类型参数(type parameter)的类或者接口,就是泛型类或者接口
(2)参数化类型(parameterized type):例如,List<String>(读作“list of string”)是一个参数化的类型,表示元素类型为String的列表
(3)原生态类型(raw type):不带任何实际类型参数的泛型名称;例如,与List<E>相对应的原生态类型是List。原生态类型就像从类型生命中删除了所有泛型信息一样。

b)原生态类型的缺点与替代
原生态类型逃过了类型检查,原生态类型只是为了与引入泛型之前的遗留代码进行兼容和互用而提供的。
(1)为什么会有泛型 list<E>
如果没有泛型的话,我们从一个没有定义类型的集合里面取数据的时候就不知道是什么类型,强制转换会出现ClassCastException异常
这时候原生态类型就需要升级->泛型,有了泛型的规约这种情况就会避免了
(2)参数化类型 list<Object>:参数化类型的存在原因同泛型
(3)Set<?>:无限制的通配符类型(unbounded wildcard type)
如果要使用泛型,但不确定或者不关心实际的类型参数,就可以使用一个问号代替

c)总结
Set<Object>是个参数话类型,表示可以包含任何对象类型的一个集合;
Set<?>则是一个通配符类型,表示只能包含某种未知对象类型的一个集合;
Set则是个原生态类型,它脱离了泛型系统。
前两种是安全的,最后一种不安全。

第24条:消除非受检警告
使用编译器完成代码编写的时候,可能会有黄色的波浪线提示警告,不要忽略它,每一处警告可能都是一个ClassCastException,可以使用
@SuppressWarnings("uncheched")消除警告,这个声明可以作用的范围十分广泛,类、方法、变量上都可以,尽可能的使作用范围小一些,在声明这个注解的时候最好加上注释,注明理由为什么这里是安全无须检查?

第25条:列表优先于数组
数组与泛型相比,有两个重要的不同点
(1)区别1
首先,数组是协变的(convariant)。相反泛型则是不可变的(invariant)。
//这是被允许的
Object[] objectArray = new Long[1];
objectArray[0] = "hello world";//Throws java.lang.ArrayStoreException

//Won't compile! 不被允许:Type mismatch: cannot convert from LinkedList<Long> to List<Object>
List<Object> list = new LinkedList<Long>();

(2)区别2
数组是具体化的(reified)。因此数组会在运行时才知道并检查他们的元素类型约束。泛型是通过擦除来实现的。因此泛型只在编译时强化他们的类型信息,并在运行时丢弃(或者擦除)他们元素的类型信息。

创建泛型数组是非法的:
//Cannot create a generic array of List<String>
List<String>[] stringLists = new List<String>[1];

一般来说,数组和泛型不能很好的混合使用。


第26条:优先考虑泛型
用泛型比使用需要在客户端代码中进行转化的类型来的更安全。也更容易,在设计新类的时候,要确保它们不需要这种转换就可以使用。这通常意味着要把类做成是泛型的。

第27条:优先考虑泛型方法
型方法就像泛型一样,使用起来比要求客户端转换输入参数并返回值的方法来的更加安全,也更加容易。就像类型一样,你应该确保新的方法可以不用转换就能使用,这通常意味着要将它们泛型化。并且就像类型一样,还应该将现有的方法泛型化,使新用户使用起来更加轻松,且不会破坏现有的客户端。

第28条:利用有限制通配符来提升API的灵活性 (有事例代码)
如果参数化类型表示一个T生产者,就使用<? extends T>,如果表示一个T的消费者,就使用<? super T>。

第29条:优先考虑类型安全的异构容器 (有事例代码)
集合API说明泛型的用法:限制容器只能由固定数目的类型参数。
可以通过将类型参数放在键上而不是容器上来避开这一限制
对于类型安全的异构容器,可以用Class对象作为键,以这种方式使用的Class对象称作类型令牌

事例代码

猜你喜欢

转载自blog.csdn.net/charjay_lin/article/details/81050261