In the following example:
public static void main(String[] args) {
List b = new ArrayList();
first(b);
second(b);
List<List<String>> is not same as List<List<?>>. Generics are invariant in nature. If you only do List<?> and pass List<String> then it will work because List of Anything can be represented by Lists of String.
But List of List of anything can not be represented by List of List of String.
@Lukas Elder has already specified case that will work. Here is the second case that will work
private static void fourth(List<?> a){
System.out.println("List of anything ");
}
A List<List<String>> isn't a List<List<?>>.
You should be able to put any List<?> into a List<List<?>>, no matter what the ?. A List<List<String>> will only accept a List<String>.
List<List<?>> == List { //That contains any unknown type lists
List<Integer>,
List<String>,
List<Object>
}
Where as
List<? extends List<?> == List { //That contains same unknown type lists
List<Integer>,
List<Integer>,
List<Integer>
}
So here
List<List<String>> == List { //That contains same String lists
List<String>,
List<String>,
List<String>
}
Hence List<? extends List<?> is super type of List<List<String>> and assignable.
So valid value to call your fourth method is below.
List<List<?>> a1 = new ArrayList<List<?>>();
a1.add(new ArrayList<String>());
a1.add(new ArrayList<Integer>());
a1.add(new ArrayList<Object>());
If you want to be able to call fourth with a List<List<String>> argument, then you'll need to change your signature to this:
private static void fourth(List<? extends List<?>> a){
System.out.println("List of a List of anything ");
}
The above will work because unlike List<List<?>>, List<? extends List<?>> is compatible with List<List<String>>. Think of it this way:
List<List<String>> original = null;
List<? extends List<?>> ok = original; // This works
List<?> ok2 = original; // So does this
List<List<?>> notOk = original; // This doesn't
List<Integer> original = null;
List<? extends Number> ok = original; // This works
List<?> ok2 = original; // So does this
List<Number> notOk = original; // This doesn't
The reasoning is simple. If you had
private static void fourth(List<List<?>> a) {
List<?> ohOh = Arrays.asList(new Object());
a.add(ohOh);
}
And then if you could call that method as such:
List<List<String>> a = new ArrayList<List<String>>();
fourth(a);
String fail = a.get(0).get(0); // ClassCastException here!
This implies that the type is unknown and objects of any type can be added to
List<List<?>>that areheterogeneousand compiler cannot guarantee that all object inList<List<?>>are of same type. Hence it cannot be passed to newArrayList<List<String>>()that takes a bounded type as parameter.