Here's a link to a good explanation Difference between <? super T> and <? extends T> in Java
The book is correct "? super String" means that the list may contain Strings or a supertype of String (eg. Object, CharSequence)
In you example:
List<? super String> superString = new ArrayList<>();
superString.add(new String());// 1
superString.add(new Object()); // 2
Write operations:
1 - is valid for any type of list you could've created , since String is an Object, a CharSequence...
List<? super String> list = new ArrayList<Object>();
list.add("String");
2 - not valid because it doesn't cover all cases
List<? super String> list = new ArrayList<String>();
list.add(new Object());
Given the declared type List<? super String>
you can only add Strings (and String subtypes) , anything less than a String (supertypes) may not correspond to the actual element type.
Example:
Here's an example :
interface MyInterface {
}
class MyInterfaceImpl implements MyInterface {
}
class MyInterfaceImplExtra extends MyInterfaceImpl {
}
You may have the following situations:
List<? super MyInterfaceImpl> myList = new ArrayList<MyInterfaceImpl>();
Doesn't compile because myList variable may point to a list of either MyInterfaceImpl or MyInterface or Object. When adding to the list it's unclear exactly what kind of list you actually have, thus you are allowed only values that are applicable for all cases.
myList.add(new MyInterface(){}); // - compile error "not applicable for the arguments"
myList.add(new MyInterfaceImpl()); // - works fine
myList.add(new MyInterfaceImplExtra()); // - works fine
An example where you get a list of values. The element type is Object , a more concrete type can't be guaranteed. For example here you expect Strings but get a List<? super String>
that actually contains Objects so you get a java.lang.ClassCastException
List<String> result = (List<String>) getList();
System.out.println(result.get(0));
public static List<? super String> getList(){
List<Object> list = new ArrayList<Object>();
list.add(new Object());
return list;
}
Usage example in Java 8 :
You have the following method declaration in the Stream interface that restricts the predicate type to be T or supertype.
Stream<T> filter(Predicate<? super T> predicate);
This ensures that given a class Person that defines name and Employee that extends Person and defines an extra field id , you can't do something like this:
List<Person> list = new ArrayList<Person>() {{
add(new Person("John"));
add(new Person("Max"));
add(new Person("Megan"));
}};
list.stream().filter((Employee e) -> e.getId().startsWith("1")); // compile error