Search code examples
javagenericsjava-6nested-generics

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>>`)

Solution

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