72

Why we can't do

List<Parent> mylist = ArrayList<child>();
skaffman
  • 398,947
  • 96
  • 818
  • 769
Ismail Marmoush
  • 13,140
  • 25
  • 80
  • 114
  • 7
    Nitpick: The `Parent` / `Child` metaphor is weird when discussion inheritance, since inheritance describes an *is a* relation. (Would you say a `Child` *is a* `Parent`?) – aioobe Jun 17 '15 at 20:58
  • 1
    Because a family tree or hierarchy is often used as an analogy for a Java type hierarchy. Although semantically you have a point. – cellepo Nov 14 '18 at 03:43

3 Answers3

141

Suppose we could. Then this program would have to be fine:

ArrayList<Banana> bananas = new ArrayList<Banana>();
List<Fruit> fruit = bananas;
fruit.add(new Apple());

Banana banana = bananas.get(0);

That's clearly not type safe - you've ended up with an apple in the collection of bananas.

What you can do is:

List<? extends Fruit> fruit = new ArrayList<Banana>();

this is safe, because the compiler won't then let you try to add to the list of fruit. It knows that it's a list of some kind of fruit, so you could write:

Fruit firstFruit = fruit.get(0);

but it doesn't know what exact kind of fruit it's a list of, and make sure you can't do the wrong thing.

See the Java generics FAQ another explanation.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 3
    I like this explanation a lot. – nfechner Apr 23 '11 at 10:56
  • Jon, you just related my question about AlignmentAssigner to this; I implemented the extends notation, and it works. One question: when I passed the filled array to the utility method extending my interface, that List changed type to the generic. Is it possible to have a method extend an interface, work on data implementing that interface, and then pass it back as the *original* type? My only hiccup is that I had to cast the newly generic List as using my implementation class. – rainydaymatt Jun 15 '15 at 18:02
  • @rainydaymatt: Not without making the type itself generic, no. Otherwise how would you preserve the information about which type of list you had? – Jon Skeet Jun 15 '15 at 18:39
  • I completely disagree with this line of argumentation. It's one thing to store a Banana as a Fruit; it's another to store a List as a List. – Andrew Feb 01 '17 at 19:55
  • @Andrew: I'm not sure what you're arguing against then. I've explained why you *can't* treat a `List` as a `List`. – Jon Skeet Feb 01 '17 at 20:08
  • In literal response to the original question, yes, you are correct; however, what is actually intended (not stated but intended) is for Bananas to be stored in a List. – Andrew Feb 01 '17 at 20:18
  • @Andrew: I see no indication of that in the question. The question explicitly asks why we can't assign a value of type `ArrayList` to a variable of type `List`. My answer explains that, and was accepted - what makes you think you know the OP's mind better than they do themselves? – Jon Skeet Feb 01 '17 at 20:24
  • Because I give him the benefit of the doubt of wanting to do something sensible but not quite understanding how it works. The sensible thing that he would want to be doing in order to come to that question of his is to store Bananas in a Fruit List even though the List is of Fruits. What he would not know by your answer is that he can e.g. extract Bananas out of the List and place them into the Fruit List. Then his intent makes sense, even though his question does not. – Andrew Feb 01 '17 at 21:55
  • @Andrew: I see no reason not to think that the OP meant exactly what they asked. Similar questions have been asked very many times. When a question is clearly expressed - and the answer accepted without further comment - I would avoid trying to second-guess the questioner. Just because *you* find the question as written obvious doesn't mean the questioner did. (And it's still not clear in what way you "completely disagree with this line or argumentation" either.) – Jon Skeet Feb 01 '17 at 22:47
  • You mistook me: I wasn't second-guessing the questioner. I was saying your line of argumentation isn't robust. Hence "I completely disagree with this line of argumentation." The questioner was doing what the questioner always does. You however answered his question with tunnel vision, and you still can't see that or at least won't admit it. The point of his asking is to learn, not to have a super literal answer; he needs to understand, not just have an accepted answer. Anyways we're wasting our time now. – Andrew Feb 02 '17 at 02:45
  • @Andrew: "I wasn't second-guessing the questioner." Yes, you were. You were guessing what they were unclear about beyond what was in the question. Unless you know the OP personally, you're guessing there. "I was saying your line of argumentation isn't robust." *Which* line of reasoning? The line of reasoning in my answer *is* robust, and explains clearly why the OP's code won't and shouldn't compile, which is what they asked. One thing we can agree on: this argument is a waste of time. I'm pretty confident in my ability to understand what questioners are looking for. – Jon Skeet Feb 02 '17 at 06:52
5

Because they're not the same type. Suppose you had another child class of Parent (Child2 for the sake of argument), it would then be possible to put an instance of Child2 into a List<Parent>, but type-incorrect to put it into an instance of List<Child>. Covariant inheritance is a real headache, and is only supported at all in Java for array types (where it can cause odd problems).

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
-3

It should be this way, because we can do: Parent A = new Child();

Edit : Wait, actually it works :

List<Parent> list = new ArrayList<Parent>(); List<ChildA> tmp = new ArrayList<ChildA>(); list.addAll(tmp); List<ChildB> tmp2 = new ArrayList<ChildB>(); list.addAll(tmp2);

It's just that the direct cast is not supported.