Why we can't do List<Parent> mylist = ArrayList<child>();

26,749

Solution 1

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.

Solution 2

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).

Share:
26,749
Ismail Marmoush
Author by

Ismail Marmoush

You can check my website and blog https://marmoush.com

Updated on July 24, 2020

Comments

  • Ismail Marmoush
    Ismail Marmoush almost 4 years

    Why we can't do

    List<Parent> mylist = ArrayList<child>();
    
    • aioobe
      aioobe about 9 years
      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?)
    • cellepo
      cellepo over 5 years
      Because a family tree or hierarchy is often used as an analogy for a Java type hierarchy. Although semantically you have a point.
  • nfechner
    nfechner about 13 years
    I like this explanation a lot.
  • rainydaymatt
    rainydaymatt about 9 years
    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.
  • Jon Skeet
    Jon Skeet about 9 years
    @rainydaymatt: Not without making the type itself generic, no. Otherwise how would you preserve the information about which type of list you had?
  • Jake88
    Jake88 almost 8 years
    This may be the FAQ you were referencing: angelikalanger.com/GenericsFAQ/FAQSections/…
  • Jon Skeet
    Jon Skeet almost 8 years
    @Jake88: Thanks, edited.
  • Andrew
    Andrew over 7 years
    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<Banana> as a List<Fruit>.
  • Jon Skeet
    Jon Skeet over 7 years
    @Andrew: I'm not sure what you're arguing against then. I've explained why you can't treat a List<Banana> as a List<Fruit>.
  • Andrew
    Andrew over 7 years
    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<Fruit>.
  • Jon Skeet
    Jon Skeet over 7 years
    @Andrew: I see no indication of that in the question. The question explicitly asks why we can't assign a value of type ArrayList<child> to a variable of type List<parent>. My answer explains that, and was accepted - what makes you think you know the OP's mind better than they do themselves?
  • Andrew
    Andrew over 7 years
    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.
  • Jon Skeet
    Jon Skeet over 7 years
    @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.)
  • Andrew
    Andrew over 7 years
    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.
  • Jon Skeet
    Jon Skeet over 7 years
    @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.