Can someone explain why the following code does not compile:
ArrayList<List<?>> arrayList = new ArrayList<List<String>>();
Why is the above code invalid but this one is running fine:
ArrayList<?> items = new ArrayList<List<String>>();
Can someone explain why the following code does not compile:
ArrayList<List<?>> arrayList = new ArrayList<List<String>>();
Why is the above code invalid but this one is running fine:
ArrayList<?> items = new ArrayList<List<String>>();
Copyright © 2021 Jogjafile Inc.
Let's start with simple lists. Integer is a subclass of Number, so you can assign Integer to a Number:
Now, let's have a
List<Number>. Shouldn't we be able to put aList<Integer>there?No, it fails. Why? Because generics in Java are invariant, that means for any two different types T1 and T2 neither
List<T1>is a subtype ofList<T2>norList<T2>is a subtype ofList<T1>regardless of relations between T1 and T2. Ok, this formally explains why the above assignment is invalid, but what is the logic behind this?The
List<Number>should be able to hold any number, that means that if we have a declarationthen we should be able to do
number.add(Integer(42)),number.add(Double(Math.PI))and any othernumber.add(subClassOfNumber). However, if the above assignmentwould be valid, then
numberswould now hold the list, which is only capable of storing Integers, sonumbers.add(anyNumberButInteger)would have failed, which violates the contract ofList<Number>.It is possible to create a list, which will hold instances of some subclass of Number:
You can read this list without a problem:
However you can't put anything there except null, because it's not possible to know the exact type of list elements at compile time and thus is not possible to make the check for safety:
Well, now to your example:
In order this assignment to work you actually need to have on the left side a
List<? extends List<String>>, but since Java generic is invariant, the only type which extendsList<String>isList<String>itself, so the only valid combination isIt is possible to create a variable which represent a list, which is composed of some lists by using raw types:
TLDR: the only generic class which is super/extends
List<String>isList<String>, soList<some class which extends List<String>>automatically meansList<List<String>>.