I love the answer from @Bert F but this is the way my brain sees it.
I have an X in my hand. If I want to write my X into a List, that List needs to be either a List of X or a List of things that my X can be upcast to as I write them in i.e. any superclass of X...
List<? super X>
If I get a List and I want to read an X out of that List, that better be a List of X or a List of things that can be upcast to X as I read them out, i.e. anything that extends X
List<? extends X>
Hope this helps.
这两个是在编译器做类型擦除(自动帮我们转换类型)时起作用
extend是producer,用于获取,如果容器里都是某个类的子类的话,那么编译器可以安全的将其类型转换为基类或接口赋给某给基类或接口的引用
super是consumer,用于添加,如果容器是都是某个类的超类的话,那么编译器可以安全的把要放进去的这个类的子类转换为超类的类型后赋值给某个位置的元素