Generics: Почему приведение с подстановочными знаками и наоборот разрешено в методе передачи параметров?

У меня есть следующий код:

public static void swap(List<?> list) {
    swapHelper(list); //1
}

private static <E> void swapHelper(List<E> list) {
    swap(list); //2
}

{
    List<?> tW = new ArrayList<>();
    List<E> tE = new ArrayList<>();

    tW = tE; // 3
    tE = tW; // 4
}

В этом коде строки 1 и 2 успешно компилируются, не значит ли это: я могу назначить ссылки на List<?> к тому из List<E> и наоборот? Если так, то почему строка 4 не компилируется.

1 ответ

И то и другое <?> а также <E> неизвестные типы; но все List<?>s имеют элементы некоторого типа, так что вы можете вызвать метод, чей параметр List<E>потому что есть какой-то неизвестный тип, который соответствует ему.

Обратите внимание, что вы не можете сделать это:

public static void swap(Object object, List<?> list) {
    swapHelper(object, list); // Compiler error: object not in bounds of list.
}

private static <E> void swapHelper(E object, List<E> list) {
    swap(object, list); // OK.
}

потому что теперь вы не знаете, если Object находится в пределах List<?>,

Также вы не можете добавить новые ненулевые значения в список:

private static <E> void swapHelper(List<E> list) {
    list.add(new E());  // Can't create an instance of type variable.
    swap(list);
}

но вы можете добавить значения, которые вы берете из списка, поскольку они, как известно, находятся в пределах списка:

private static <E> void swapHelper(List<E> list) {
    list.add(list.get(0));
    swap(list);
}

так что это тип безопасно сделать вызов оригинала swapHelper от swap, поскольку вы не можете вызвать что-то, что не поддается E (каким бы ни был этот тип) в список.

Аналогично с tW а также tE:

  • Если вы назначите tW = tEВы не можете ничего добавить к tW Кроме как nullтак что нельзя поставить tE в состоянии, где он содержит что-либо, кроме случаев E,
  • Если вам было разрешено назначить tE = tWВы можете добавить ненулевые экземпляры E в tE, Это может означать, что вы можете добавить экземпляр неправильного класса в tW, что может привести к ошибкам типа во время выполнения. Таким образом, это назначение запрещено.

Помните, что назначение списка не приводит к копированию списка: если вы назначаете tE = tW, затем tE == tWтак что все изменения применяются к tE также видны через tW, так как они один и тот же экземпляр.

Другие вопросы по тегам