Несоответствие типичного типа Java
В следующем примере:
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 ");
}
Почему вызов второго (б) работает, но вызов четвертого (а) не?
Я получаю следующую ошибку:
The method fourth(List<List<?>>) in the type `TestTest` is not applicable for the arguments (`List<List<String>>`)
Ответы
Ответ 1
Если вы хотите иметь возможность вызывать fourth
с аргументом List<List<String>>
, вам нужно будет изменить свою подпись на это:
private static void fourth(List<? extends List<?>> a){
System.out.println("List of a List of anything ");
}
Вышеупомянутое будет работать, потому что в отличие от List<List<?>>
, List<? extends List<?>>
совместимо с List<List<String>>
. Подумайте об этом так:
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
Простые рассуждения. Если у вас
private static void fourth(List<List<?>> a) {
List<?> ohOh = Arrays.asList(new Object());
a.add(ohOh);
}
И тогда, если вы могли бы вызвать этот метод как таковой:
List<List<String>> a = new ArrayList<List<String>>();
fourth(a);
String fail = a.get(0).get(0); // ClassCastException here!
Ответ 2
A List<List<String>>
не является List<List<?>>
.
Вы можете поместить любой List<?>
в List<List<?>>
, независимо от того, что ?
. A List<List<String>>
принимает только List<String>
.
Ответ 3
Это означает, что тип неизвестен, а объекты любого типа могут быть добавлены в List<List<?>>
, которые являются heterogeneous
, а компилятор не может гарантировать, что все объекты в List<List<?>>
имеют одинаковый тип. Следовательно, он не может быть передан новому ArrayList<List<String>>()
, который принимает ограниченный тип в качестве параметра.
Ответ 4
List<List<String>>
не совпадает с List<List<?>>
. Дженерики носят инвариантный характер. Если вы выполняете только List<?>
и проходите List<String>
, тогда он будет работать, потому что List of Anything
может быть представлен Lists of String
.
Но List of List of anything
не может быть представлено List of List of String
.
@Lukas Elder
уже указал случай, который будет работать. Вот второй случай, который будет работать
private static void fourth(List<?> a){
System.out.println("List of anything ");
}
Ответ 5
List<List<?>> == List { //That contains any unknown type lists
List<Integer>,
List<String>,
List<Object>
}
Где
List<? extends List<?> == List { //That contains same unknown type lists
List<Integer>,
List<Integer>,
List<Integer>
}
Итак, здесь
List<List<String>> == List { //That contains same String lists
List<String>,
List<String>,
List<String>
}
Следовательно, List<? extends List<?>
является супер-типом List<List<String>>
и присваивается.
Допустимое значение для вызова метода fourth
приведено ниже.
List<List<?>> a1 = new ArrayList<List<?>>();
a1.add(new ArrayList<String>());
a1.add(new ArrayList<Integer>());
a1.add(new ArrayList<Object>());