The compiler stops us here. If we pass
List<Object>
, which would be a legal argument for
dest
, and
T
is set as
Number
like when we instantiated the class, then we would potentially be returning something like a
String
, which is a subtype of
Object
, but obviously not of
Number
. The lower bound cannot give us any guarantee on the types of objects we read from the list so it cannot act as a producer. If we need a generic type to act as both a producer and consumer, then we cannot use any bound at all. In the case of
List
it needs to be
List<T>
. This provides the flexibility of being a producer or consumer, but we lose the flexibility of of using inheritance with the type parameters. In general, it is better practice to use a lower or upper bound as the parameterized type in the method if we know if it will be acting as either a producer or consumer and not both.
A quick review in summary:
- PECS = Producer-Extends, Consumer-Super
- No bounds on the type parameter such as
List<T>
allows it to be a producer or consumer. The downside is we can’t utilize the inheritance hierarchy on T
.
List<? extends T>
allows subclasses of T
to be used as an argument. The downside is that the list becomes immutable.
List<? super T>
allows T
and any super class to be used as an argument. The downside is that there are no guarantees on the type contained so we can only put elements into it and cannot fetch them inside our method definition.