EffectiveJava-4-泛型

115 阅读3分钟

请不要在新代码中使用原生态类型

- 如不要使用List,而是使用List(泛型),形式类型参数E表示列表的元素类型;

- 由于java 20岁时才有泛型,为了保证移植兼容性,java仍旧支持原生态类型;

- 如果使用原生态类型,就失掉了泛型在安全性和表述性方面的所有优势;

例如下面代码:

- 在类文字中必须使用原生态类型,不允许使用参数化类型,如String[].class,List.class,不能使用List.class,List<?>.class等

消除非受检警告

- 用泛型编程时,会遇到许多编译器警告
- 非受检强制转化警告
- 非受检方法调用警告
- 非受检普通数组创建警告
- 非受检转换警告

- 要尽可能的消除每一个非受检警告,以确保代码是类型安全的(否则可能会在运行时出行ClassCastException):

- 如果无法消除警告,同时可以证明引起警告的代码是类型安全的,可以用@SuppressWarnings("unchecked")注解来禁止这条警告,最好添加注释说明为什么是安全的, 应在尽可能小的范围中使用该注解,如果在长度不止一行的方法或构造器中使用该注解,可将其移到一个局部变量的声明中,例如下面这样:

列表优先于数组

- 两个不同点

1. 数组是协变的, 如果Sub是Super的子类,那么数组Sub[]也是Super[]的子类;
而泛型则是不可变的List和List不存在父子关系;
正因如此,数组在这一点上是存在缺陷的,请看下面例子:

2. 数组是具体化的,在运行时才知道并检查它们的元素类型约束;
而java中的泛型只存在于编译期,以强化类型信息,在运行时丢弃(擦除)其元素类型信息,.class中是没有泛型的;(擦除就是使泛型可以与没有使用泛型的代码随意进行互用,也是为了兼容泛型出现前的代码)

综上原因,创建泛型数组 new List[],参数化类型数组 new List[],类型参数数组new E[],这些都是非法的

优先考虑泛型

将类泛型化,尽量使用泛型代替Object,如用E[] 代替Object[],
例如下面代码:

优先考虑泛型方法

- 如同类泛型化一样,泛型方法也具有类型检查的优势,无需明确指定类型参数的值,更加安全,也便于使用,尤其是静态工具方法,非常适合泛型化;

- 递归类型限制:通过某个包含该类型参数本身的表达式来限制类型参数,如 <T extends Comparable>;

利用有限制通配符来提升API的灵活性

- 我们知道参数化类型是不可变的,如List与List不存在父子关系(A is B 的关系),其所带来的优势就是类型安全,可以解决25.1中的问题,然而有些时候却不够灵活;
例如下面代码中的pushAll_1()和popAll_1()使用时的问题:

- 类型参数和通配符选择哪个?请看下面代码:

优先考虑类型安全的异构容器

- 泛型的常见用法是这样List,Map<K,V>,ThreadLocal,充当被参数化了的容器,但这限制了每个容器只能有固定数目的类型参数,如:List只有一个类型参数T代表其元素类型;

- 一种解决方案:将键(key)进行参数化而不是将容器参数化,然后将参数化的键提交给容器来插入或者获取值,用泛型系统来确保值的类型与它的键相符,就行下面代码这样:

我是今阳,如果想要进阶和了解更多的干货,欢迎关注公众号”今阳说“接收我的最新文章