Jargon warning — it’s rather abstract to talk about “super-types .. sub-types”, so I will use Number (a real super-type), Integer etc in this post.
ArrayList<Number> liNum = new …;
ArrayList<Integer> liInt = new ..;
Rule 0 —- The method myCollection.add() is tolerant, lenient and easy. Wildcard never needed for add().
liNum.add(100); // fine
Rule 1 —- cast/assignment/param-passing is stricter than add()
Rule 1a —- A List-of-subtype can’t be cast to List-of-SUPERtype.
Rule 1b —- A List-of-SUPERtype can’t be cast to List-of-subtype.
As a result, a method parameter declared as type A will not accept an argument of the type B, and vice-versa. Parameter passing is assignment.
There’s no “subsumption” between types A and B. See P16[[java generics]] for the (simple) reasons. STL has similar restrictions
ArrayList<Integr> tmp5 = liNum; // wont’ compile
ArrayList<Number> tmp3 = liInt; // won’t compile
 See P662 [[Programming]] by Stroustrup. Given a vector of ptr2shapes, producer can insert ptr2square but consumer may expect a ptr2Circle!
Now, what if my method wants to accept any list of number, or list of int, or list of float etc? (In other words, i want to accept a List-of-SUPERtype or a List-of-any-subtype?)
Rule 2 —- use wildcard to accept list-of-Number-OR-list-of-Integer
In other words, ArrayList<? extends Number> is a SUPERtype of ArrayList<Integer>. P18 [[java generics]].
ArrayList liWild6 = liNum; //ok
ArrayList liWild1 = liInt; //ok
I feel this is about the only common usage of wildcard.