简体   繁体   中英

Java nested generic type mismatch

In the following example:

public static void main(String[] args) {

    List<String> b = new ArrayList<String>();
    first(b);
    second(b);

    List<List<String>> a = new ArrayList<List<String>>();
    third(a);
    fourth(a);  // doesnt work

}

private static <T> void first(List<T> a){
    System.out.println("List of T");
}

private static void second(List<?> a){
    System.out.println("List of anything ");
}

private static <T> void third(List<List<T>> a){
    System.out.println("List of a List of T ");
}

private static void fourth(List<List<?>> a){
    System.out.println("List of a List of anything ");
}

Why does the call to second(b) work, but the call to fourth(a) doesn't ?

I get the following error:

The method fourth(List<List<?>>) in the type `TestTest` is not applicable for the arguments (`List<List<String>>`)

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<?>> 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!

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> .

This implies that the type is unknown and objects of any type can be added to List<List<?>> that are heterogeneous and compiler cannot guarantee that all object in List<List<?>> are of same type. Hence it cannot be passed to new ArrayList<List<String>>() that takes a bounded type as parameter.

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 ");
}
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<?> 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>());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM