Craig Chan
Craig Chan

Reputation: 31

Understanding use of wild card in java generics?

I have asked a similar question and this is a more specific version in the hope of getting a clear answer. While trying to understand java generic types and usage of wild card "?", I tried the following:

List<Integer> li4 = new ArrayList<Integer>();
  li4.add(new Integer(5));
  Integer myInt4 = li4.get(0);

Now I replace with the more generic type '

List<? extends Integer> li = new ArrayList<Integer>(); 
Integer myInt = li.get(0);

The above compiles fine. It seems that 'li' above is being treated as a list where each element is an Integer (look at the li.get(0) call). I can also do the following:

li = li4;

The above compiles and runs fine. But when I try:

li.add(new Integer(5));

I get following compilation error (using Oracle JDeveloper as IDE):

 Error(24,9):  cannot find method add(java.lang.Integer)

'? extends Integer' should allow any types that extend Integer. It behaves like that for the 'get' method where it returns an Integer. Similarly it does not complain when ArrayList is assigned to it. So for example 'li = new ArrayList<String>()' does not compile. So why am I allowed to assign another ArrayList<Integer>(), get an Integer back but not add an Integer?

Upvotes: 0

Views: 200

Answers (2)

Craig Chan
Craig Chan

Reputation: 31

Following code helped me understand the answer:

    List<Exception> exL = new ArrayList<Exception>();
    exL.add(new Exception());
    Exception ex = exL.get(0);
    Throwable th = exL.get(0);
    exL.add(new NullPointerException());
   /** Error(153,7):  cannot find method add(java.lang.Exception)
    exL.add(new Throwable());
   **/

So when we declare List, the elements must at least have behavior of Exception which means Exception, RuntimeException and its sub-classes. It is ok to assign an element returned from such a list to either Exception or any of its subclasses. "Exception e = exL.get(0)" Or "Throwable th = exL.get(0)". It is also ok to add an instance of Exception or say NullPointerException to List.

List genExcepList, can be a List, List or List as "? extends Exception" represents Exception and all its sub-classes. In fact, List is a super class of List, List etc. For any of these list types, the returned element from 'get' call is guaranteed to be of type Exception. So it is ok to do: Exception e = genExcepList.get(0). But it is not ok to call genExcepList.add(exception) as List must satisfy the restrictions on every type it allows which are List, List, List etc. The only thing that works is genExcepList.add(null) as 'null' would work for every type. On the other hand if we have something like: List rtgs = new ArrayList(); "? super Exception" represents Exception and any its super-classes. So List represents List, List and List. On any of these list types, one can call "add(new Exception());" so it is ok to call rtgs.add(new Exception()) as an Exception is also a Throwable and Object. However, it is not ok to call "Exception ex = rtgs.get(0)" as the element returned from List can be any of Exception, Throwable and Object. So the only thing that would safely work is "Object ex = rtgs.get(0)".

Upvotes: 0

Louis Wasserman
Louis Wasserman

Reputation: 198033

? extends Integer does not mean "should allow any types that extend Integer". It means that this is a List<T> for some specific T that extends Integer.

So anything you get out of a List<? extends Integer> will extend Integer, but you can't just put anything in -- we don't know that the type you're putting in matches T.

To give a concrete example, Integer extends Number. So you could write

List<? extends Number> list1 = new ArrayList<Integer>();
List<? extends Number> list2 = new ArrayList<Double>();

But you shouldn't be allowed to write list2.add(new MyNumber()), or list2.add(new Integer(3)), because list2 is actually a List<Double>.

Upvotes: 5

Related Questions