У меня есть переменная e4
типа List<List<Integer>>
, которую я бы хотел инициализировать new ArrayList<ArrayList<Integer>>()
. Я ожидаю, что это сработает, подобно тому, как можно назначить переменной List<Integer>
-type new ArrayList<Integer>()
. Вместо этого возникает ошибка компиляции; какова причина этого, и нужно ли тогда использовать такое утверждение, как e3
или e5
?
import java.util.List;
import java.util.ArrayList;
public class Example {
public static void main(String[] args) {
// e1-3 compile as expected
ArrayList<Integer> e1 = new ArrayList<Integer>();
List<Integer> e2 = new ArrayList<Integer>();
ArrayList<ArrayList<Integer>> e3 = new ArrayList<ArrayList<Integer>>();
// e4 does not compile
List<List<Integer>> e4 = new ArrayList<ArrayList<Integer>>();
// e5 does compile
List<ArrayList<Integer>> e5 = new ArrayList<ArrayList<Integer>>();
}
}
При попытке скомпилировать выше, я получаю сообщение об ошибке:
/home/james/Example.java:12: error: incompatible types
List<List<Integer>> e4 = new ArrayList<ArrayList<Integer>>();
^
required: List<List<Integer>>
found: ArrayList<ArrayList<Integer>>
1 error
Причина в том, что List<ArrayList<Integer>>
не является List<List<Integer>>
, хотя ArrayList<Integer>
является List<Integer>
. Обоснование здесь аналогично тому, что List<Dog>
не является List<Animal>
, хотя Dog
является Animal
. Аналогия заключается в том, что ArrayList<Integer>
означает List<Integer>
поскольку Dog
для Animal
.
Ниже приведены альтернативы:
1) Ваш "e5", который точно соответствует типичному типу.
List<ArrayList<Integer>> e5 = new ArrayList<ArrayList<Integer>>();
или
List<List<Integer>> e5 = new ArrayList<List<Integer>>();
2) Использование подстановочного знака:
List<? extends List<Integer>> e6 = new ArrayList<ArrayList<Integer>>();
Whenever you are specifying ;
List<List<Integer>> e4 = new ArrayList<ArrayList<Intger>>();
This stands out to be wrong because when you are creating the ArrayList (Implementation of the List) e4 you are specifying that it can contain List (all kinds of implementation of lists) of Integer but while instantiating it you are strictly specifying it as ArrayList of Integer which is contradicting with your declaration.
Moreover Polymorphism only applies to the base type (Base type means the collection class itself.)
Your example can be correlated with another example :
List<Number> l1= new ArrayList<Integer>(); /*This will never compile though Integer is a subclass of Number as we are not only changing the base type but also the generic type which is wrong.*/
But this will definitely compile
List<Number> l2 =new ArrayList<Number>(); //Changed only the base type.
For better understanding read Sun Certified Programmer for Java 6 by Kathy Sierra and Bert Bates.
Как работает java
List<List<Integer>> list = new ArrayList<ArrayList<Integer>>
не будет работать, потому что внутренний ArrayList не соответствует типу List. Он ищет именно список.
Вы хотите следующее
List<? extends List<Integer>> list = new ArrayList<ArrayList<Integer>>();
Причина в том, что дженерики в Java инвариантны. Сначала рассмотрим очень простой пример:
// This doesn't compile
List<Number> list = new ArrayList<Integer>();
Вышеприведенное назначение не будет компилироваться, потому что ArrayList<Integer>
не является подтипом List<Number>
, хотя Integer
является подтипом Number
.
Используя эту концепцию для вложенных дженериков:
// This also shouldn't compile
List<List<Integer>> list = new ArrayList<ArrayList<Integer>>();
Хотя ArrayList<Integer>
является подтипом List<Integer>
, это не делает ArrayList<ArrayList<Integer>>
подтипом List<List<Integer>>
. Поэтому он не компилируется.
Чтобы скомпилировать его, вы можете использовать ограниченные подстановочные знаки:
// This would work now.
List<? extends List<Integer>> list = new ArrayList<ArrayList<Integer>>();