2

I am reading book for OCP of Author Jeanne Boyarsky and Scott Selikoff, Book saying : Page # 122

? super String

With a lower bound, we are telling Java that the list will be a list of String objects or a list of some objects that are a superclass of String

    List<? super String> superString = new ArrayList<>();
    superString.add(new String());// Valid 
    superString.add(new Object()); // Not Valid ? Why?. Object is a super class of String 

Other Example:

List<? super IOException> exceptions = new ArrayList<Exception>();
exceptions.add(new Exception()); // Invalid, why ? Exception is a superclass of IOException
exceptions.add(new IOException());
exceptions.add(new FileNotFoundException());

I think this statement

With a lower bound, we are telling Java that the list will be a list of String objects or a list of some objects that are a superclass of String

Should be

With a lower bound, we are telling Java that the list will be a list of String objects or a list of some objects whoes super class is String

if this case is true then why we use

List<? super IOException> exceptions = new ArrayList<Exception>();

instead of

List<? super IOException> exceptions = new ArrayList<IOException>();
Shahid Ghafoor
  • 3,049
  • 14
  • 58
  • 108

2 Answers2

2

You need to understand, that these bounds (lower and upper) exist for restricting/specifying the variable's type, and not for restricting/specifying the type of elements inside such a collection.

An example:

List<? super String> variable = new ArrayList<CharSequence>();

With this statement, you first create an ArrayList whose elements can be of type CharSequence or a subtype of it (e.g. String or StringBuilder).

With that declaration it should be clear that you can not add an Object into this list. It simply does not implement the CharSequence interface. The compiler takes care of that.

Lower and upper bounds exist for making subtypes of generic types. Their use is explained in this question about PECS.

In fact, a List<? super String> is a list with a concrete element's type, but this concrete type is not known at this moment. See my example initialisation. The concrete type is the CharSequence. It simply means that all elements are of that concrete type (or a subtype), but that is not known in the variable's own type.

Community
  • 1
  • 1
Seelenvirtuose
  • 19,157
  • 6
  • 34
  • 57
  • In other words: to the variable one can assign a list of some super type (String, CharSequence, Object), and the compiler can only know that Strings may be put safely in the list. – Joop Eggen Jun 22 '16 at 08:31
  • `List super IOException> exceptions = new ArrayList(); exceptions.add(new Exception()); // Invalid, why ? Exception is a superclass of IOException exceptions.add(new IOException()); // if we really need to create list why this is valid exceptions.add(new FileNotFoundException());// and this one also valid ` can u please give a complete example. I am still confused. – Shahid Ghafoor Jun 22 '16 at 16:15
  • @ShahidGhafoor It is invalid, because you could have initialized the variable like that: `List super IOException> exceptions = new ArrayList()`. You are not allowed to add an `Exception` into such a list. The compiler must forbid that. – Seelenvirtuose Jun 23 '16 at 19:33
1

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
Community
  • 1
  • 1
Katrinna L
  • 1,360
  • 3
  • 16
  • 24
  • `? super String" means that the list may contain Strings or a supertype of String (eg. Object, CharSequence)` can u please give complete example where `? super String` take both String and supertype Object. bcz answer still not clear for me .. thanks – Shahid Ghafoor Jun 22 '16 at 13:44