Why A->B doesn't make List<A>->List<B>? Wouldn't that remove need for wildcards?

喜夏-厌秋 提交于 2019-12-06 11:03:59
Lagerbaer

There's a simple reason.

Suppose you have a variable of type List<A>. Suppose List<B> was indeed a subtype of List<A>.

That means that when this would be legal:

List<A> a_list;
a_list = new List<B>(); //allowed when List<B> is subtype of list<A>
a_list.add(new A()); // WOAH!

Where I say WOAH, the following happens: You add an item of type A to a_list. Since a_list was declared as List<A>, this should be legal. But wait: a_list is pointing to something of type List<B>.

So now we add something of type A to a list that should store only items of type B, and this is clearly not what we want, since A is not a subclass of B!

If List<B> was a subtype of List<A> the following code would be legal, as java does remove most of the Generic magic at compile time. (If that was a good decision or not is a different topic).

public void addNewAToList(List<A> list) {
    list.add(new A());
}


public static void main(String[] args) {
    List<B> listB = new LinkedList<B>();
    addNewAToList(listB);       // <--- compiler error
    for (B b : listB) {         // <--- otherwise: there is an A in the list.
        System.out.println(b);
    }
}

The problem is that if you have class C extends A and are given a List<A>, you can put a C in because a C is an A. But if Java allowed you to just give the method a List<B>, then you're putting a C in a list of Bs. And a C is not a B, so there'll be an error down the line. Java's wildcard solution doesn't let you add anything but null to a List<? extends A>, saving you from this mistake.

Well, Comeau c++ online compiler fails on this:

template<typename T> class List {
};

class A {
};

class B: public A {
};

void function(List<A> listA) {
}

int main(int argc, char** argv) {
    List<A> a;
    List<B> b;

    function(a);
    function(b);
}

giving this error:

"ComeauTest.c", line 18: error: no suitable user-defined conversion from "List<B>" to
          "List<A>" exists
  function(b);

So C++ and Java are similar when dealing with these kinds of types.

Static typing dictates that a subtype must support all operations of its supertype.

List<Fruit> supports inserting Fruit objects.

List<Banana> does not -- you cannot insert arbitrary fruits into a List<Banana>, only bananas.

Hence, List<Banana> is not a subtype of List<Fruit>.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!