Generics and inheritance?

public static void main(String... args) {
    List<Child> list1 = new ArrayList<Child>();
    method2(list1);
}

public static void method2(List<Parent> list1) {
}   

      

I am getting below compilation error

Method method2 (List) undefined ...

The above problem can be resolved by changing List<Parent> list1

to List<? extends Parent> list1

.

But if i try to add child object like below

public static void method2(List<? extends Parent> list1) {
    Child child1 = new Child();
    list1.add(child1);
}

      

It gives compilation error again

The add (capture # 1-of? Extends Parent) method on the List type is not applicable for the (Child) arguments

So my question is, if List<Child>

it is possible to pass as a parameter to List<? extends Parent> list1

, why can't we add a child to List<? extends Parent>

?

+3


source to share


4 answers


This is a very common misunderstanding. The fact that Child extends Parent does not extend List<Child>

List<Parent>

. It sounds very unintuitive, as in this case, but there is. From the java tutorial:

Given two specific types A and B (for example, number and integer), MyClass <A> is irrelevant to MyClass <B>, regardless of A and B. The common parent of MyClass and MyClass is an object.

Read this for more details .



As for adding to a list, the short answer is: Imagine you have another one class Child2 extends Parent

, now the list you receive as a parameter in method2(List<? extends Parent> list1)

can be List<Child1>

either List<Child2>

, So given that the second case is possible, adding a Child1 object is not safe type.

Now, the fact that you cannot add does not mean that you cannot do other useful things like getting the size, etc.

+6


source


So my question is, if List<Child>

it is possible to pass as a parameter to List<? extends Parent>

list1

, why can't we add a child to List<? extends Parent>

?

Suppose we could. Now suppose we had:

class Parent {}
class Mother extends Parent {}
class Father extends Parent {}

static void m(List<? extends Parent> parents) {
    parents.add(new Father());
}

List<Mother> mothers = new ArrayList<>();
m(mothers);
// throws 'ClassCastException: cannot cast Father to Mother'
Mother actuallyAFather = mothers.get(0);

      

A List<? extends Parent>

is a list that stores at most, Parent

or perhaps some subtype Parent

that we no longer know about. We cannot add anything to it except null.

So, perhaps you want:



public static void method2(List<? super Child> list1) {
//                                ^^^^^^^^^^^
    Child child1 = new Child();
    list1.add(child1);
}

      

A List<? super Child>

is a list that we can add a Child

to. Maybe this, List<Parent>

or maybe this List<Child>

, but we don't care. We don't care if it's a List, we can add a Child

to.

Also see:

+1


source


From Wildcards

List<? extends Parent>

is an example of a restricted template.? denotes an unknown type, just like the wildcards we saw earlier. However, in this case, we know that this unknown type is in fact a subtype Parent

.

So make sure your class Child

extends the class Parent

. then below code will work.

public static void method2(List<? extends Parent> list1) {

      

With this change, it should work by seeing the Output of your program

0


source


Here is my own answer after reading more material

We cannot assign List<Dog> to List<Animal>

because it List<Animal>

means that we can add any animal to it like cat, dog whereas List<Dog>

means we can only add dogs / subtypes to it, but not cats. So the assignor will think it will only get the dog / subtypes but it can also get the cat object (so runtime error)

Here's an example

psvm{
List<Dog> list1 = new ArrayList<Dog>();
list1.add(new Dog()); 
method1(list1);// compilation error
}

public static void method1(List<Animal> list1) {
list1.add(cat); // Good
list1.add(dog); // Good
}

      

Another common misconception is upper bounded generalizations which are exactly the opposite

When we say List<? extends Animal> list1

, we cannot add any value other than null, but yes, we can assign any Animal / Sub types.If we allow addition, that means it can contain any animal, such as a cat, a dog, but when retrieving ( i.e. dropping) we don't make it actually a type.

psvm{
List<Dog> list1 = new ArrayList<Dog>();
list1.add(new Dog()); 
method1(list1);// good
}

public static void method1(List<? extends Animal> list1) {
list1.add(cat); // compilation error
list1.add(dog); // compilation error
}

      

0


source







All Articles