As you have discovered by yourself, an ArrayList
declared as ArrayList<? extends Foo> subFoos = new ArrayList<>();
would not be very useful.
In order to see the usefulness of <? extends T>
consider this:
List<Foo> collect( List<? extends Foo> a1, List<? extends Foo> a2 ){ List<Foo> collected = new ArrayList<>(); collected.addAll( a1 ); collected.addAll( a2 ); return collected;}
which can later be used as follows:
List<Foo> foos = collect( new ArrayList<Foo>(), new ArrayList<Bar>() );
or as follows:
List<Foo> foos = collect( new ArrayList<Bar>(), new ArrayList<Foo>() );
note that none of the above would have worked if the collect
method had been declared as follows:
List<Foo> collect( List<Foo> a1, List<Foo> a2 )