Java泛型的上界下界

最近写代码时,使用了泛型的容器类,但是却一直发现编译报错.搜到一片文章 Java通配符与extends/super的PECS原则,感觉还是不太理解. 自己写了一段代码测试下:

class A {
}

class B extends A {
}

class C extends B {
}

class D extends C {
}

public class Test {

    public static void main(String[] args) {
        List<? extends B> extendsList = new ArrayList<>();
        extendsList.add(new C());
        B b = extendsList.get(0);

        List<? super B> superList = new ArrayList<>();
        superList.add(new C());
        B b1 = superList.get(0);
    }
}

extendsList.add(new C()); 会报错

B b1 = superList.get(0); 也会报错的

? extends B

extendsList的元素类型为 B或B的子类. 所以extendsList可以是List<B>,List<C>,List<D>,或者任何继承自B类的子类.

  • 当add时,因为允许extendsList为List<D>,所以添加一个C的话,会报错.而且因为extendsList的类型可能为B的任意子类(类型不确定),所以添加任意类型都会报错(包括new Object()).

  • 当get时,元素为B或B的子类,都可以安全向上转型为B(A a = extendsList.get(0)也是可以的.),所以编译可以成功.

? super B

superList的元素类型为 B或B的父类. 所以superList可以是List<B>,也可以是List<A>,或者List<Object>.

  • 当add时,因为superList为B和B的父类,所以添加B和B的子类(C,D)时,是可以向上转型为B和B的父类,编译可以成功.

  • 当get时,元素为B或B的父类,B的父类是不能转型为B,所以编译报错.但是所有的类都可以转型为Object,所以可以使用Object o = superList.get(0);

PECS原则

  • 如果想从集合get元素,并限制add元素(不可以add任意类型的元素),则可以使用<? extends T>,限制上界(Producer extends, 生产者只有get操作,不能add)。
  • 如果想给集合add元素,并限制get元素(get的元素只能是Object),则可以使用<? super T>,限制下界(Consumer super, 消费者只能add,不能get)。
  • 如果不想限制get和add,则不用通配符,List<T>就可以。

转载请注明:张浩的博客 » 点击阅读原文