Подтвердить что ты не робот

ArrayList с использованием компилятора addAll() показывает различное поведение с дженериками

Может кто-нибудь объяснить мне следующее поведение?

У меня есть список X и используйте метод addAll() для добавления элементов. Эти элементы возвращаются методом, использующим общие типы. Метод getA() возвращает < T extends A >, когда A является классом. Метод getI() возвращает < T extends I > с I, являющимся интерфейсом (см. Код ниже).

Разница: с listX.addAll(getA()) Я получаю ошибку компиляции (как и ожидалось), но listX.addAll(getI()) компилирует (выдает ошибку времени выполнения, когда элемент отличен до X).

Упрощенный код:

interface I {}
class A implements I {}

class X {}

public void test() {   
    List<X> listX = new ArrayList<>();
    listX.addAll(getA());

    listX.addAll(getI());
    for (X x : listX) {}
}
public <T extends A> List<T> getA() {
    return new ArrayList<>();
}
public <T extends I> List<T> getI() {
    return new ArrayList<>();
}

Я что-то упустил? Разве я не должен получать ошибку компиляции в оба раза?

Такое поведение кажется новым с Java 8, с версиями ниже я получил ошибки компилятора в обоих случаях.

4b9b3361

Ответ 1

Я хотел бы упростить вопрос и ответить Шмозелю следующим образом:

interface I {}
class A implements I {}

class X {}

public void test() {   
    X temp = getI();  // compiles
    X temp2 = getA();  // does not compile
}

public <T extends I> T getI() {  
    return null;
}
public <T extends A> T getA() {  
    return null;
}

getI() может потенциально возвращать то, что расширяет X и реализует I, поэтому он компилируется. Обычно тип, который он фактически возвращает, будет зависеть от чего-то, например аргумента, переданного в функцию.

getA() не может вернуть что-то, что является X, так как он возвращает то, что расширяет A, которое не расширяет X.

Ответ 2

listX.addAll(getA()); не компилируется, потому что нет возможного подкласса X, который также является подклассом A.

listX.addAll(getI()); выполняет компиляцию, поскольку может существовать подкласс X, который также реализует I.