Effective Java 读书笔记(4)

    23,在新代码里不用使用raw type。用了泛型之后,可以提供编译时类型检查,便于及早发现错误,从集合里读取数据的时候也不用手动的cast。如果真的想向集合里插入多种类型的数据,可以使用Object作为参数类型,比如List<Object>这样的。有点要注意的是class literal不能是泛型,只能有List.class,不能有List<String>.class这样的。由于泛型信息在编译时会被擦除,因此,instanceof操作符也不能和泛型进行比较,可以写if(set instanceof Set)或者if(set instanceof Set<?>),但是不能写if(set instanceof Set<String>) 。
    24,去掉unchecked警告。如果实在消除不掉,而且又确定代码是类型安全的,可以使用@SuppressWarnings("unchecked"),这个做法其实也很常见, jdk的代码里都有,不过在使用这个注解的时候,一定要注意让它的作用域尽可能的小,能写在语句上就不要写在函数上。作者举了ArrayList.toArray这个方法来作为反面例子。不过我个人以为作者在这方面有点吹毛求疵了。
    25,List优先于数组。数组是协变(covariant)的,而泛型是不能协变的,这就是说,如果Sub是Super的子类型,那么Sub[]也是Super[]的子类型,而List<Sub>不是List<Super>的子类型。还有个区别是数组是具体化的(reified),在运行时,数组都知道自己的元素是什么类型,而泛型的信息在编译后就被擦除了,运行时得不到了,这样才能和以前的没有使用泛型的旧代码兼容。基于以上这两大区别,所以不能创建泛型数组,不能使用new List<E>[], new List<String>[],new E[]这样的语句。但是泛型数组还是可以存在的,比如E[] a = (E[])list.toArray();  最终结论是不要混用数组和泛型,如果真的这么混用了而产生编译错误或警告,那还是改用List吧。
    26,在自己的代码里使用泛型。
    27,使用泛型方法。不得不说,把方法变成泛型之后,方法签名长了很多啊,不知道是不是没有类型推导的原因,还要在方法修饰符和返回值之间在声明一次泛型参数列表,原本的public static Set union(Set s1, Set s2)现在变成了public static <E> Set<E> union(Set<E> s1, Set<E> s2),看起来极其啰嗦。到了JDK1.7,终于支持构造函数的类型推导了,再也不用写冗长的Map<String, String> = new HashMap<String, String>()了,可以写成Map<String, String> = new HashMap<>()了。
    28,使用有界通配符来增强API的灵活性。也就是? extends E或者? super E这样的。还有就是不要在返回类型里使用通配符。
    29,使用类型安全的混杂容器。说实话,我觉得纵然书里吹的好,如果需要把不同的类型混杂在一个容器里,还是raw类型用起来方便。
    看完这一章之后,我感觉如果当时不是扩展旧的容器类,而是新造一套泛型容器,比如叫GList, GMap这样的名字,抛弃兼容性的包袱,也许泛型可以被设计的更好用。现在这样,感觉虽然能用,但是不好用,写起来又啰嗦。所以虽然大家广泛的使用JDK提供的泛型类,但是自己在代码里写泛型的就不多了。

你可能感兴趣的:(Effective Java)