> Another generics overriding question -- say I have the method below:
>
[quoted text clipped - 10 lines]
>
> Can anyone explain this to me? Thanks!
It's pretty much the same as the other question. You can only upcast the
result of any method to a supertype of the return type. List<Foo> is not a
supertype of List<? extends Foo>. So you get the error that you cannot
convert the type.
Start here:
<http://java.sun.com/docs/books/tutorial/extra/generics/index.html>
in particular, the topics
<http://java.sun.com/docs/books/tutorial/extra/generics/subtype.html>
and
<http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html>
address this matter.
Let's say the actual runtime return type of the list were 'List<FooSomeSub>'.
Your list 'l' would allow
l.add( new FooSomeOtherSub() );
which would violate the type safety.
The wildcard form prevents such add()s (from the referenced tutorial):
> Since we don't know what the element type of c stands for, we cannot add objects to it. The add() method takes arguments of type E, the element type of the collection. When the actual type parameter is ?, it stands for some unknown type. Any parameter we pass to add would have to be a subtype of this unknown type. Since we don't know what type that is, we cannot pass anything in. The sole exception is null, which is a member of every type.
> On the other hand, ... we can call get() and make use of the result.
Another tutorial:
<http://java.sun.com/docs/books/tutorial/java/generics/index.html>
particularly
<http://java.sun.com/docs/books/tutorial/java/generics/subtyping.html>
and
<http://java.sun.com/docs/books/tutorial/java/generics/wildcards.html>
And for the final word, the JLS:
<http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.5>
<http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.10>
> Subtyping does not extend through generic types: T <: U does not imply that C<T> <: C<U>.
<http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.10.2>
The relevance of the subtype relationship:
<http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.1.5>
<http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.4>
<http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.4.5>
<http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12>

Signature
Lew
> Another generics overriding question -- say I have the method below:
>
[quoted text clipped - 10 lines]
>
> Can anyone explain this to me? Thanks!
Basically the same problem. You could return a List<Bar> from
getFooList, then put a vanilla Foo into it via l, if you could assign
the List<? extends Foo> to l. And then somewhere else in your code,
far, far away from the real error in space and time, something would
blow up when it retrieved Bars from the list and stumbled over the
vanilla Foo. You'd get a ClassCastException from nowhere near the real
source of the problem, and possibly after a long time had gone by and
the culprit's trail had grown cold. Indeed, it might not blow up for
days; the bad item might lurk in the list like a ticking bomb while
it's ignored, then serialized to disk, then loaded in another session,
then seralized again to stream over the net to a completely different
process running on a different machine ...
Java's type checking and rules may seem strict and sometimes
mysterious, but they are designed to stop that kind of thing and make
sure that when bugs do occur, they usually produce their symptoms
close to the actual site of the logic error, making it far quicker and
far easier to debug.
Two things to further reduce the occurrence of symptoms widely
separated from causes:
* Think carefully before subverting the type system, e.g. by passing
lots of stuff around as Objects, not using generic type parameters on
containers, or sprinkling code liberally with
@SuppressWarnings("unchecked") -- this doesn't mean never do those,
but keep stuff like that to a minimum and to where you can mentally
"prove" the type-correctness of the code. I tend to limit this sort of
thing to the few cases where the type semantics can't be expressed in
Java and the compiler can't prove it's type-correct, but I know for a
fact it's safe -- and those occasions are rare indeed. Usually the
right <? extends Foo> in place of <Foo> or similar is all that's
needed.
* When using collections or otherwise storing objects for an
indeterminate time before use, check for invalid objects (nulls if
invalid, wrong type, NaNs or other unwanted float values, etc.) and
throw an exception eagerly instead of letting whoever ends up
retrieving the object have to cope with it. This is especially
critical when a parameter is stored in an object's fields or a
collection and it shouldn't be null. A single "if (foo == null) throw
new NullPointerException()" in the constructor or whatever method can
save many an hour of grief and hair-pulling down the line. This also
applies if for some reason you have need to store specific types of
object in a less specific type container (or reference). For instance,
you need to store both Baz and Quux but not accept the raw supertype
Foo or other subtypes like Bar. Ideally, there's a type for just the
things you will allow in that store, so Foo has Bar and Allowed
subclasses, and Allowed has Baz and Quux, and you use a List<Allowed>.
Of course, you might not control the classes Baz and Quux (they're
another team's code, or library code, or whatever) to be able to force
this class hierarchy. Then you need to check types explicitly,
unfortunately, or find another solution (such as separate lists for
each allowed type). Many times there are elegant ways to solve these
problems using generics. For instance, when the types of two things
need to match, instead of say xList<Foo> and yList<Foo> and a possible
mismatch with a Bar in the xList and a Baz in the corresponding place
in the yList, make a Pair<T> class with a Pair(T x, T y) constructor,
getX and getY methods, etc., and use a List<Pair<? extends Foo>>. (Of
course, this can be defeated by creating Pair<Foo>s instead of
Pair<more derived type>s, but this may still be useful partly because
what's really supposed to represent a single list is now actually a
single list instead of two, and because of cases where it's fairly
heterogeneous, particularly Foo == Object and you want Pair<Integer>s,
Pair<String>s, etc., like for some kind of comparison and validation
of heterogeneous data nuggets. Pairs with different types presumably
represent a bug in the code putting the pairs in, or validating input,
rather than one of the mismatches you want to detect later.)