0

I understand the difference between wildcard ? and type T

However unable to understand below code where in the method m3 I am passing a collection of type String.
Now in the method m3 when I try to add a String to the collection it does not allow me with an exception:

The method add(T) in the type List is not applicable for the arguments (String)

However in method m4 we are extracting an Element from the List and then adding it again.

<1> if T extends String then in method m3 why is it not allowing to add a String ?

<2> in method m4 when I am extracting an object from the List - and adding it again - this is allowed. Is it because when I extract the object is of type T and hence when adding it is allowed ?

Kind of strange behavior - I think I am getting a faint idea of why this happens but would be great to hear thoughts from others ?

package generics.wildcardVsT;

import java.util.ArrayList;
import java.util.List;

public class Ex1 {
public static void main(String[] args) {
    System.out.println("hello");
    List <String> list1 = new ArrayList<String>();
    List <String> list2 = new ArrayList<String>();
    List <String> list3 = new ArrayList<String>();
    List <String> list4 = new ArrayList<String>();
    list4.add("abc");

    m1(list1);
    m2(list2);
    m3(list3);
    m4(list4);
}

/** no compilation errors **/
public static void m1(List<String> list) {
    list.add("abc");
}

/** this will not compile because of wildcard - this is understood **/  

public static void m2(List<? extends String> list) {
    list.add("abc");
}
/** this is not understood - why will this not compile ? **/    
public static <T extends String>void m3(List<T> list) {            
 list.add("abc");   
}

/** strangely this actually compiles ! **/
public static <T extends String>void m4(List<T> list) {
    list.add(list.get(0));
}

}

satish marathe
  • 1,073
  • 5
  • 18
  • 37
  • 2
    Why are you surprised that `m3` doesn't compile? And if you expect it to compile, why are you surprised about `m4`? – shmosel Aug 01 '18 at 00:28
  • *<1> if T extends String* you can **not** `extend String` because it is `final`. And a `String` does not `extend` String it **is** a `String`. Now if you tried `CharSequence` you might have more luck. –  Aug 01 '18 at 05:05

1 Answers1

2

m3 takes T, some class that happens to extend String but list.add("abc"); is adding a String to a list of T

T could be class SuperCoolString extends String { ... } in which case list.add("abc"); would be wrong.

m4 is just adding a T element to list

I don't think that you can/should normally extend String but that's not really important here ...

pal
  • 942
  • 1
  • 9
  • 19
  • 2
    Note that it's not actually possible to extend `String`, but the compiler doesn't realize that. – shmosel Aug 01 '18 at 00:30
  • 1
    Interestingly enough, `String` is `final`. – Logan Aug 01 '18 at 00:30
  • So this seems to be the same behaviour as wildcard istnt it - where too you cannot modify the collection ( add ) except adding null. So really how different is T from ? in this case. Yes I agree that I should not have given an example of T extends String - that was only for demonstrating the issue – satish marathe Aug 01 '18 at 12:09
  • I think that you're right; `T extends String` is no different from `? extends String` in this case. – pal Aug 01 '18 at 13:55
  • @satishmarathe It's different in that you can add an instance of `T`, as in `m4`. – shmosel Aug 02 '18 at 16:58