I try to understand generics behaviour in java

I write same code:

common part:

class A1{}
class B1 extends A1{}
class C1 extends B1{}

case 1:

        List<? extends B1> list = new ArrayList<C1>();
        list.add(new A1());// compile error
        list.add(new B1());//compile error
        list.add(new C1());//compile error

case 2:

        List<? super B1> list = new ArrayList<A1>();
        list.add(new A1());//compile error
        list.add(new B1());//valid
        list.add(new C1());//valid

I think that I wrote simmetrical code. Why I see non-simmetrical results?

有帮助吗?

解决方案

List<? extends B1> means: a list of an unknow type, which is or extends B1. So it could be a List<B1>, a List<C1>, or a List<Foo> if Foo also extends B1 or C1. So you can't add anything to such a list:

list.add(new A1); // incorrect, since A1 doesn't even extend B1
list.add(new B1()); // incorrect, since the list could be a List<C1>
list.add(new C1()); // incorrect, since the list could be a List<Foo>

The only thing you can add to such a list is null.

List<? super B1> means: a list of an unknow type, which is B1 or a superclass or superinterface of B1. So it could be a List<B1>, a List<A1>, or a List<Object> (and nothing else). So

list.add(new A1()); // incorrect, since the list could be a List<B1>, and A1 is not a B1
list.add(new B1()); // valid, since whatever the type of the list (B1, A1 or Object), B1 is of this type
list.add(new C1()); // valid, since whatever the type of the list (B1, A1 or Object), B1 is of this type

If you try to get an element from such a list, though, you can't have any guarantee about its type. The only sure thing is that it's an Object.

The general principle is PECS: Producer Extends, Consumer Super. This means that when a list is a producer (which means you want to get elements from it), then extends should be used. When the list is a consumer (which means you want to add elements to it), then super should be used.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top