method - java generics parameter
ArrayList utilizando el compilador addAll() muestra un comportamiento diferente con genéricos (2)
Esta pregunta ya tiene una respuesta aquí:
- ¿Por qué compila este código genérico en java 8? 3 respuestas
¿Alguien me puede explicar el siguiente comportamiento?
Tengo una lista de X
y uso el método addAll()
para agregar elementos. Estos elementos son devueltos por un método que utiliza tipos genéricos. El método getA()
devuelve < T extends A >
siendo A
una clase. Método getI()
devuelve < T extends I >
siendo I
una interfaz (ver código a continuación).
Diferencia: con listX.addAll(getA())
Obtengo un error de compilación (como se esperaba), pero listX.addAll(getI())
compila (arroja un error de tiempo de ejecución cuando el elemento se convierte en X
).
Código simplificado:
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<>();
}
¿Me estoy perdiendo de algo? ¿No debería obtener un error de compilación en ambas ocasiones?
Ese comportamiento parece ser nuevo con Java 8, con versiones inferiores obtuve errores de compilación en ambos casos.
Me gustaría simplificar la pregunta y la respuesta de Shmosel de la siguiente manera:
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 () puede potencialmente devolver algo que amplíe X e implemente I, por lo que compila. Normalmente, el tipo que realmente devuelve dependerá de algo, por ejemplo, un argumento pasado a la función.
getA () no puede devolver algo que sea una X, ya que devuelve algo que se extiende A, que no extiende X.
listX.addAll(getA());
no compila porque no hay una posible subclase de X
que también sea una subclase de A
listX.addAll(getI());
compila porque podría haber una subclase de X
que también implementa I