effective Java第5章-泛型

本文章是自己看完effective Java第5章后的一点笔记,看完后觉得自己以前基本就是一个不晓得泛型是啥的人。

有了泛型,可以告诉编译器的每个集合中接受哪些对象类型,编译器会自动在插入时进行转换,并在编译时告诉你是否插入了错误的对象。

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

​ 意思为不在代码中写

List list = new ArrayList()

上面的代码为原生态类型,在1.5版本前这样写是可以加入不同类型的对象,但是在取出时,强转往往会出错。错误嘛,越早发现越好,最好编译期间就发现,不然就是一颗雷。那为什么有了泛型后,在创建容器对象时制定类型就行了呢?泛型到底干了什么呢?

泛型编译时强化他们的类型信息,并在运行时擦除,在编译时会检查其元素类型信息,但在运行时丢弃其元素类型信息。

于是编译期间就能够发现是否插入了不符合类型要求的对象(其子类,会自动转为父类,编译器会帮你进行装换),还有一点很重要,** List< String >是List的子类型,但不是List< Object >的子类型**。

泛型中的"?",为无限制的类型通配符,读做每个类型的集合。表示任意类型的集合都可以,但不能将任何元素(除了null)加入Collecion<?>。

    static int test(Set<?> s1, Set<?> s2){
        int result = 0;
        for(Object o : s1){
            if( s2.contains(o) ){
                result++;
            }
        }
        return result;
    }

public static void main(String[] args) {
        Set<String> s1 = new LinkedHashSet<>();
        Set<Object> o1 = new LinkedHashSet<>();
        test(s1,o1);
}

消除非受检警告

​ 意思就是尽可能的减少警告,如果遇到了不可能发生错误的警告代码可以使用@SuppressWarning("unchecked")注解来禁止这条警告。但是始终应该在最小范围内使用@SuppressWarning("unchecked")注解。

列表优先于数组

​ 列表与数组的区别

  1. 数组是协变得,即如果sub是super的子类型,则sub[]是super[]的子类型,而列表是不可变的list与 list没有什么关联。

    Object[] objects = new Long[1];
    objects[0] = "asdf,zxc";
    以上在运行时才会报错
    List<Object> objets2 = new ArrayList<Long>;
    objects2.add("asdf");
    以上代码编译期间会报错
    
  2. 数组是具体化的,因此数组会在运行时才知道并检查他的类型,而泛型是擦除的来实现的。因此泛型只在编译时强化他们的类型信息,并在运行时丢弃(或擦除)他们的元素类型信息。擦除是使泛型可以与没有使用泛型的代码随意进行使用。

因为前面的2个原因所以数组与泛型不能共用 new List[],E[],new List[],都会编译期出错。

书中的建议是:当你发现自己将数组与列表混合使用,并得到了编译时的警告或者错误时,应该用列表代替数组

优先考虑泛型与泛型方法

​ 泛型与泛型方法都更加便于在编译期间发现问题,且使用性更加强大

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

​ 什么是有限制通配符呢?

Collection<? extends E>();
Collection<? super E>();

因为泛型不是协变得,于是很多时候将其子类的集合传入会报错,此时就可以使用有限制通配符来解决这个问题。

书中还提出了一个很好的观点PECS表示producer-extends,consumer-super,意思就是对于消费集合中的元素的也就是使用集合中的元素的使用super,往集合中添加元素的,extends更加好。详细解释更建议看书