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

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

I get below compilation error

The method method2(List) is undefined ...

Above issue can be solved with modifying 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 method add(capture#1-of ? extends Parent) in the type List is not applicable for the arguments (Child)

So my question is if List<Child> can be passed as parameter to List<? extends Parent> list1 why we can't add child object under List<? extends Parent>?

Cœur
  • 37,241
  • 25
  • 195
  • 267
M Sach
  • 33,416
  • 76
  • 221
  • 314
  • pls post the def for Child and Parent class – Stephan May 15 '15 at 12:56
  • 1
    See the PECS rules. You could have a class `Child2 extends Parent`. If it was allowed then you could add a `Child` instance to a `List`. – Alexis C. May 15 '15 at 13:00
  • As an unrelated note, I start twitching every time I see `class Child extends Parent {}`. Children should not be parents!!! [LSV](http://en.wikipedia.org/wiki/Liskov_substitution_principle). `Parent parent = new Child();` is a nonsensical analogy for inheritance. – Radiodef May 15 '15 at 13:29
  • That's because you are thinking of Child and Parent in terms of biology, not class relationships. The fact that he never mentioned that Child extended Parent and everyone understood the question is telling. – Daniel Langdon May 15 '15 at 13:36
  • @DanielL. In fact, I often see parent/child used *specifically* as a biological analogy (see e.g. [this tutorial](http://www.htmlcenter.com/blog/object-oriented-programming-parents-and-children/) which I found on the first page of Google). Also, we would have understood the question if the OP used `class Gidget extends Gadget {}`. Could have been anything. Anyway, I wasn't criticizing the question. – Radiodef May 15 '15 at 15:01

3 Answers3

6

This is a very common misunderstanding. The fact the Child extends Parent does not make List<Child> extend List<Parent>. Sounds very unintuitive in cases like this one, but there it is. From the java tutorial:

Given two concrete types A and B (for example, Number and Integer), MyClass< A> has no relationship to MyClass< B>, regardless of whether or not A and B are related. The common parent of MyClass and MyClass is Object.

Read this for details.

As for adding to the list, the short answer is: Imagine you have a another class Child2 extends Parent, now, the list you are receiving as a parameter at method2(List<? extends Parent> list1) could be either a List<Child1> or a List<Child2>. Thus, given that the second case is possible, adding a Child1 object is not type safe.

Now, the fact that you can't add does not mean that you can't do other useful stuff, like getting the size, etc.

Daniel Langdon
  • 5,899
  • 4
  • 28
  • 48
  • Second case is also showing compile time error `...is not applicable for the arguments (Child2)` – TSKSwamy May 15 '15 at 13:15
  • Of course, it is perfectly symmetric. I was giving an example of why it would fail for both given that you can't know what actual type of object is in your list, not saying that it would work for Child2 – Daniel Langdon May 15 '15 at 13:18
  • Really its very confusing. Looks like i have to mug up this one which i don't like. – M Sach May 16 '15 at 13:51
  • Another way to explain this would be this: You method receives a parameter "list of something that extends Parent", not knowing what 'something' is. Thus, you are limited to the operations that do not require to know it: attributes of the list, picking an element and using it as a normal Parent pointer, etc. On the other hand, you can't add a new 'something' without knowing what it should be. – Daniel Langdon May 16 '15 at 15:35
1

So my question is if List<Child> can be passed as parameter to List<? extends Parent> list1 why we can't add child object under 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 which stores at most Parent, or perhaps some subtype of Parent, which we don't have knowledge of anymore. We can't add anything to it except null.

So perhaps what you want is:

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

A List<? super Child> is a List which we can add a Child to. Maybe it's a List<Parent> or maybe it's a List<Child>, but we don't care. We only care that it's a List we can add a Child to.

Also see:

Community
  • 1
  • 1
Radiodef
  • 37,180
  • 14
  • 90
  • 125
0

Here is my own answer after reading more stuff

We can not assign List<Dog> to List<Animal> because List<Animal> means we can add any animal like cat, dog to it whereas List<Dog> means we can add only dog/sub types to it but not cat. So assigner will think he will get only dog/sub types but he can get cat object also(so run time error)

Here is the 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 about upper bounded Generics which is exactly opposite of

When we say List<? extends Animal> list1 we can not add any value except null but yes we can assign any Animal/Sub types If we allow adding it means it can contains any animal like cat, dog but while retrieval(i.e down-casting) we don't what actually it is type of.

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
}
M Sach
  • 33,416
  • 76
  • 221
  • 314