问题
Disclaimer: I'm not a professional developer, and I'm not intending to become one. Reading book about Java, as I wanted to try Android programming, no previous Java experience whatsoever.
I'm reading this book - and I rather like it. I've read part of chapter about generic classes, got to the point where they mention wildcards, and got confused.
If B extends A:
List<B>is not a subtype ofList<A>(as I understand it they're exactly the same)List<? extends B>is a subtype ofList<? extends A>
The latter allows for writing functions that accept arguments that are of generic type - for example List<? extends A>. Such function would accept an argument of either List<B> or List<A>.
Now, for my question:
Wouldn't it be simpler to implement generics in a manner similar to C++ (in a "template" flavour)? This would make List<B> and List<A> two separate types, that would be related in expected way. This would also allow to simply state in a function that you expect an argument to be of type List<A>, which would allow List<B> to fit there just fine.
I'm guessing there was more than "we hate C++, let's make things different" behind this :) It's also quite possible that I don't know something yet, that makes wildcards a fantastic and useful tool. What's your take on this?
Edit: if you're mentioning List<X> in your answer, remember to use backticks, to avoid <X> being interpreted as HTML tag.
回答1:
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!
回答2:
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);
}
}
回答3:
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.
回答4:
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.
回答5:
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>.
来源:https://stackoverflow.com/questions/4229886/why-a-b-doesnt-make-lista-listb-wouldnt-that-remove-need-for-wildcards