Or perhaps it is really just a “typo” in the following segment from the book,
** BEGIN EXCERPT **
Now let's try an example with an interface. We have an interface and two classes that implement it.
interface Flyer { void fly(); }
class HangGlider implements Flyer { public void fly() {} }
class Goose implements Flyer { public void fly() {} }
We also have two methods that use it. One just lists the interface, and the other uses an upper bound.
private void anyFlyer(List<Flyer> flyer) {}
private void groupOfFlyers(List<? extends Flyer> flyer) {}
Note that we used the keyword extends rather than implements. Upper bounds are like anonymous classes in that they use extends regardless of whether we are working with a class or an interface. You already learned that a variable of type List<Flyer> can be passed to either method.
==> A variable of type List<Goose> can be passed only to the one with the upper bound. <== (My Emphasis)
This shows one of the benefits of generics. Random flyers don't fly together. We want our groupOfFlyers() method to be called only with the same type. Geese fly together but don't fly with hang gliders.
** END EXCERPT **
As I look at it, the more it seems obvious that the parameter to groupOfFlyers() should be of type, List<? extends Goose>, and the point being made is rather trivial. Otherwise, I can make neither heads nor tails of it. Could you please confirm whether it is in fact a mistake, in which case I have been reading too much into it.
Thank you for your attention. (And thank you for your invaluable book and your commitment of continued support of it!)
Joe Sock (Aspiring Java Developer)