4

Simple example:

public class Person
{
    String name;
}

public class VIP extends Person
{
    String title;
}

And then doing:

public static void main(String[] args)
{
    Person p = new Person();
    p.name = "John";

    VIP vip = new VIP();
    vip.name = "Bob";
    vip.title = "CEO";

    List<Person> personList = new ArrayList<Person>();
    List<VIP> vipList = new ArrayList<VIP>();

    personList.add(p);
    personList.add(vip);

    vipList.add(vip);

    printNames(personList);
    printNames(vipList);
}

public static void printNames(List<Person> persons)
{
    for (Person p : persons)
        System.out.println(p.name);
}

gives an error on "printNames(vipList)" (required List<Person> found List<VIP>).

Does this mean that although VIP is a Person, List<VIP> is not a List<Person>?

Knut Arne Vedaa
  • 15,372
  • 11
  • 48
  • 59
  • 1
    Yes, that's what it means. Duplicate: http://stackoverflow.com/questions/2033912/c-variance-problem-assigning-listderived-as-listbase – Lasse V. Karlsen Jan 25 '10 at 15:17
  • How is this a duplicate? That post asks about C#, this one about Java. The fact that they happen to work the same way doesn't mean that they have to. – danben Jan 25 '10 at 15:21
  • @Lasse - that's a C# question, this is a Java question. However, I know this question has been asked numerous times about Java, too. – Paul Tomblin Jan 25 '10 at 15:21
  • Oops, didn't notice the Java tag, my apologies, but it *is* a duplicate because all the reasons why it isn't possible in C# are exactly the same for Java. In short, if you were allowed to downcast (but not convert, note the distinction) a List{Child} to a List{Base}, the compiler would not be able to prevent you trying to add Base instances to the list. So while it is a duplicate, I should've picked a different duplicate question. The answer by BalusC is the right one, however, which is the same solution for both Java and C#, add a constraint to the method. – Lasse V. Karlsen Jan 25 '10 at 22:13

3 Answers3

11

That's right. A list of bananas is not a list of fruit. Otherwise you could insert any fruit in a list of bananas. e.g.

List<Fruit> lf = new List<Banana>();
lf.add(new Apple());

would result in unexpected or counterintuitive results.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
  • 1
    Try with List extends Fruits> lf = new List(); That way Java will know that it can be a list of "some child" and will not allow using lf.add(new Apple()) but will allow the asigment of the list. – helios Jan 25 '10 at 15:22
9

You're just prohibited by the rules of Generics. If you're rather interested in how to "fix" this behaviour, just change the printNames() method to take a List<? extends Person> argument instead.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 1
    You can almost be certain that the best tutorials are been provided by the vendor itself :) You can find them by just Googling "[keyword] tutorial site:sun.com". For example: http://google.com/search?q=generics+tutorial+site:sun.com It's already the 1st hit. – BalusC Jan 25 '10 at 15:46
1

Bjarne Stroustrup, inventor of C++, explains it rather well:

http://www2.research.att.com/~bs/bs_faq2.html#conversion

Yes, I know I am late for this party, but better than never, right..

Armen Michaeli
  • 8,625
  • 8
  • 58
  • 95