After reading your email again, I find myself agreeing. This is because I don't consider List<Integer> to be a subtype of List<Number>.
LinkedList<Number> would be a subtype of List<Number>, but inheritance doesn't really extend any further beyond that, for the reason you have illustrated. The example you gave is similar to implementing an interface with a type hint of Number, but trying to changing it to Integer. The method signatures are clearly incompatible, so I believe the same applies here in generics. On 29 Apr 2016 4:22 p.m., "Rowan Collins" <rowan.coll...@gmail.com> wrote: > guilhermebla...@gmail.com wrote on 29/04/2016 15:26: > >> You can add subtypes of A to a List<A> in Java. What List<? extends A> >>> >means is that the list itself may be a list of any type, provided that >>> type >>> >is compatible with A. So if B extends A, List<B> is compatible with >>> List<? >>> >extends A>, and when reading items you can assume they will be >>> compatible >>> >with A (since B extends A) but you can't add an A (because it's >>> actually a >>> >list of Bs). >>> > >>> > >>> >> Wrong. This is documented here >> https://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html >> and >> specifically states: >> >> To write the method that works on lists of Number and the subtypes of >> Number, >> >>> >such as Integer, Double, and Float, you would specify List<? extends >>> >Number>. The term List<Number> is more restrictive than List<? extends >>> >Number> because the former matches a list of type Number only, whereas >>> >the latter matches a list of type Number or any of its subclasses. >>> >> > > Forgive me for butting in if I'm completely wrong, but is the confusion > here between *declaring an instance* and *declaring a parameter constraint*? > > I think the point is that you can declare variables as follows: > > List<Integer> li; // only accepts Integer > List<Double> ld; // only accepts Double > List<Number> ln; // accepts any Number, even if it is in fact an Integer > or Double instance > > But if you then define a function accepting a parameter: > > public static double sumOfList(List<Number> list) > > > Now your argument has to be of type List<Number>; you can pass "ln" above, > but not "li" or "ld". To relax the function's contract, you can write this > instead: > > public static double sumOfList(List<? extends Number> list) > > Now the argument can be a List<Integer> or List<Double>, so "li" and "ld" > are legal arguments. > > > The reason the default case is to be invariant, rather than covariant, is > explained on the blog post Jesse linked to: > http://hhvm.com/blog/9215/covariance-contravariance-and-super-type-constraints > > > In a nutshell, consider this function: > > function addPiToList(List<Number> $list): void > { > $list->add(3.1415); // for the sake of example, assume 3.1415 instanceOf > Double > } > > If we allow covariance, then we can run addPiToList(new List<Integer>) and > the type conditions are met; clearly this is not sane, and is going to > result in an error somewhere. > > So we need to be stricter: > > function addPiToList(List<Double> $list): void > > But the actual contract we want here is "any list we can legally add a > Double to", and if we get a List<Number> or a List<*>, it would work fine, > so our check is too strict. What's needed is a way to declare our function > as contravariant: > > function addPiToList(List<? super Double> $list): void > > Now we can pass in a List<Double> or a List<Number>, but not a > List<Integer>, and our contract holds nicely. > > > It took me a while to get my head around, but I think the above makes > sense... > > Regards, > -- > Rowan Collins > [IMSoP] >