Ковариация и контравариантность для типов с подстановочными знаками

Не могли бы вы объяснить, почему это возможно сделать:

import java.util.ArrayList;
import java.util.List;

public class Covariance {

    class A {
    }

    class B extends A {
    }

    class C extends A {
    }

    public void testSmth() throws Exception {
        List<? extends A> la = new ArrayList<A>();
        A a = la.get(0);
        // la.add(new B()); - doesn't compile

        List<? super B> lb = new ArrayList<A>();
        // lb.add(new A()); - doesn't compile
        lb.add(new B());
        Object object = lb.get(0);
    }

}

Я не понимаю, почему нельзя что-то добавить в ковариантный список la, но можно добавить B в контравариантный список lb, но нельзя добавить A в lb.

С моей точки зрения, должно быть возможно добавить в список все, что расширяет A. Я вижу единственную причину этого не делать, потому что легко добавить C в список B, например

 List<B> lst = new ArrayList<B>();
 List<? extends A> lstB = lst;
 lstB.add(C); // this is valid for <? extends B> but list lst would contain instance of B.

Вероятно, то же самое верно и для контравариантности, например

 List<B> lst = new ArrayList<B>;
 List<? super C> lstC = lst;
 lstC.add(new C());
 Object obj = lstC.get(0);

Что я не понимаю - почему это невозможно сделать

 B b = lstC.get(0);

Очевидно, что на этом этапе super of C будет классом B — Java не допускает множественного наследования.

И почему запрещает

 lstC.add(new B());

это не ясно для меня.


person jdevelop    schedule 26.05.2011    source источник
comment
Супер из C может быть A, Object, но, что более важно, C.   -  person Tom Hawtin - tackline    schedule 26.05.2011


Ответы (2)


Чтобы понять, что происходит с ключевым словом super, рассмотрим следующее:

import java.util.ArrayList;
import java.util.List;

public class Covariance {

    class A {
    }

    class B extends A {
    }

    class C extends A {
    }

    class D extends C {}

    public void testSmth() throws Exception {
        List<? super D> ld = new ArrayList<C>();
    }

}

Надеюсь, это иллюстрирует, что ld может быть списком любого супертипа D, даже того, который является подклассом A.

person MGwynne    schedule 27.05.2011

учитывать

    List<? extends A> la = new ArrayList<C>();

это список C. Если бы мы могли добавить к нему B, это нарушило бы тип списка.

person irreputable    schedule 26.05.2011
comment
это правда. однако неясно, что происходит с ключевым словом super - person jdevelop; 26.05.2011