Java那些事-泛型通配符

Java的类型通配符,能够出如今类、方法上面。最经常使用的方式就是集合类,例如List,Set等类上面。java

通配符类型

  • 有泛型参数 List
  • 有无类型标识 List< ? >
  • 有通用的标识 List< object >
  • 边界通配符 List<? extends Class>
  • 边界通配符 List<? super Class>

本文主要讨论的是最后的关于边界的通配符类型。数组

看一个例子

public static void main(String[] args) {
        List<B> bList = new ArrayList();
        bList.add(new A());
        bList.add(new B());
        bList.add(new C());
        A a3 = bList.get(0);
        B b3 = bList.get(0);
        C C3 = bList.get(0);

        List<? extends B> bExtends = new ArrayList();
        bExtends.add(new A());
        bExtends.add(new B());
        bExtends.add(new C());
        A a1 = bExtends.get(0);
        B b1 = bExtends.get(0);
        C C1 = bExtends.get(0);

        List<? super B> bSuper = new ArrayList();
        bSuper.add(new A());
        bSuper.add(new B());
        bSuper.add(new C());
        A a2 = bSuper.get(0);
        B b2 = bSuper.get(0);
        C C2 = bSuper.get(0);
    }
}
class A {
    String a = "a";
}
class B extends A {
    String b = "b";
}
class C extends B {
    String c = "c";
}

有三个类,继承关系是A < B < C。
而后声明了三个数组,list,extends,super.
上面的代码是编译不经过的。分别在第三、七、11-1三、1六、1九、22-24行。安全

原理分析

List<? extends B> 获得的是B及B的子类的一个集合。
List<? super B> 获得的是B及B的父类的一个集合。
List 获得的是一个B的集合。code

  1. ? extends B 声明了上界标识符、不定下界,而add(E e)的时候,编译器没法肯定e须要分配的声明类型,虽然有实际类型,这个地方跟多态不一致,因此编译器不经过;而get(int i)的操做,会获取到一个确定是B的元素,故是安全的。
  2. ? super B正相反,声明的是下界标识符、不定上界(Object),当add(E e)的时候,添加的是子类型,子类型向上转型是安全的;get(int i)的时候,并不能肯定拿到的会是一个怎样的类型,多是Object,也能是A,故也是违规的。
  3. B 声明的是上下界为B。add(E e)按照多态性,能够添加为B的类型及其子类型;get(int i)返回的必然是B的类型。

代码错误验证

按照第1条解释,第三、11-13行的错误符合解释。
按照第2条解释,第1九、22-24行的错误符合解释。
第七、16行是因为向下转型是不安全的,股编译错误。继承

小结

extends和super别定义了上下限,结论以下面的表格get

extends super T
add unsafe safe safe
get safe unsafe safe
相关文章
相关标签/搜索