generics incomprehension
Hi,
I'm reading some papers about generics, but there is something i dont understand:
class A{}
A is a type
class Bextends A{}
A is a super type of B
B is a sub type of A
class Cextends B{}
B is a super type of C
C is a sub type of B and A
am i right until here ? (maybe i'm confused with english words it may explains why i dont understand the following example)
ArrayList<?super B> list1 =new ArrayList<B>();
list1.add(new A());// error
list1.add(new B());
list1.add(new C());
List of super types of B (classes A and B !?)
So why C is a correct element of the list althought it's not a super type of B ?
ArrayList<?extends B> list2 =new ArrayList<B>();
list2.add(new A());// error
list2.add(new B());// error
list2.add(new C());// error
List of sub types of B (B and C !?)
Why nothing can be added ? Even B !?
ArrayList<B> list3 =new ArrayList<B>();
list3.add(new A());// error
list3.add(new B());
list3.add(new C());
List of B and compatibles (sub type: C).
Expected behavior, nothing to add.
Thanks by advance for your help.
[2196 byte] By [
bleubleua] at [2007-11-27 3:35:28]

http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf
> http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf
page 7:
There is, as usual, a price to be paid for the flexibility of using wildcards. That price
that it is now illegal to write into shapes in the body of the method. For instance,
this is not allowed:
public void addRectangle(List<? extends Shape> shapes) { shapes.add(0, new Rectangle()); // compile-time error!
}
You should be able to figure out why the code above is disallowed. The type of
the second parameter to shapes.add() is ? extends Shape - an unknown subtype
Shape. Since we don抰 know what type it is, we don抰 know if it is a supertype
Rectangle; it might or might not be such a supertype, so it isn抰 safe to pass a Rectangle there.
it's because of this tutorial that i m posting here :)
I'm afraid i misunderstood something in.
i can write
new ArrayList<Shape>().add(new Rect())
but i can't write
(new ArrayList<? extends Shape>).add(new Rect())
?
what is the difference between these two lines ?
(new ArrayList<? extends Shape>()).add(new Rect())
You can't write this because the compiler expects a specific type in the
angle brackets, not "? extends Shape". What that code is trying to express is
"create an ArrayList of element type some unknown subclass of Shape".
That makes no sense.
class A {}
class B extends A {}
ArrayList<? extends A> list1 = new ArrayList<A>();
list1.add(new B());// error
ArrayList<A> list2 = new ArrayList<A>();
list2.add(new B());
my question was: why these two lists are differents ?!
> my question was: why these two lists are differents ?!
[url=http://en.wikipedia.org/wiki/Mu_(negative)]Mu![/url]
class A {}
class B extends A {}
ArrayList<? extends A> list1;
list1 = new ArrayList<A>();
list1 = new ArrayList<B>();
~
yawmark i dont understand your answser, sorry
list2.add(new B()) works because ArrayList<A> has the method
boolean add(A a)
and "upcasting" lets us pass a reference of type B to add. I assume that makes sense to you.
list1.add(new B()) fails because the type of list1 is ArrayList<? extends A> -- this means that the parameter type of the list is some fixed but unknown subclass of A. You can't add a reference of type B (or do list1.add(new A()) either) because of the unknown nature of this type. This implies that with such a list, you can't
add elements. You can, however access or remove elements:
A a = list1.get(0);
Such is the nature of that type expression.
> yawmark i dont understand your answser, sorry
You cannot add elements of a known type to a list expecting an "unknown subtype of A". A reference of List<? extends A> can point to a List<A> or a List<B> or a List<SomeOtherClassThatExtendsA>. But you can't add elements of a specific type to that list by calling add() through that reference.
~
> list2.add(new B()) works because ArrayList<A> has the
> method
> > boolean add(A a)
>
> and "upcasting" lets us pass a reference of type B to
> add. I assume that makes sense to you.
>
> list1.add(new B()) fails because the type of list1 is
> ArrayList<? extends A> -- this means that the
> parameter type of the list is some fixed but unknown
> subclass of A. You can't add a reference of type B
> (or do list1.add(new A()) either) because of the
> unknown nature of this type. This implies that with
> such a list, you can't
> add elements. You can, however access or remove
> elements:
> > A a = list1.get(0);
>
> Such is the nature of that type expression.
Not to be picky, but I think you got them backwards ... according to the OPs post:
list2.add(new B());// error
list1.add(new A());// error
list1.add(new B());
list1.add(new C());
so extends should be reserved for templating accessors only ?
okay, it seems ugly, but you are right, it can be explained
I understand much better, but there is still a problem:
class A {}
class B extends A {}
class C extends B {}
C is a sub type of B
A is a super type of B
ArrayList<? super B> list1 = new ArrayList<B>();
list1.add(new A()); // error
list1.add(new B());
list1.add(new C());
adding A will fail because we dont know if A is a super type of "<? super B>" ?
But why the last line don't fail ? We KNOW that C is not a super type of B !
thanks for your responses
With extends, the compiler has to deal with open-endedness, with super, there
are a fixed number of cases. Given a reference of type ArrayList<? super B>, the
actual type must be ArrayList<B>, ArrayList<A> or ArrayList<Object>.
You can't add new A() because of the first case, but you can add new B() or new C().
okay, i understood,thanks for all