El siguiente código compila sin ningún error con Eclipse, pero genera un error con javac. Parece ser un error de compilación, pero no sé cuál es el adecuado.
Me gustaría señalar que sé cómo corregir este error al cambiar el código para que funcione con ambos, pero ese no es el tema actual. Me gustaría saber si es un java o un problema eclipse.
Trato con IntelliJ pero tengo el mismo error javac.
Código de ejemplo para reproducir este error:
import java.util.ArrayList;
import java.util.List;
public class A<T extends B> {
protected List<C> list = new ArrayList<>();
class C {}
public void createIO() {
A<? extends B> x = null;
List<A<? extends B>.C> y = x.list;
}
}
class B {
}
JVM:
openjdk version "13-BellSoft" 2019-09-17
OpenJDK Runtime Environment (build 13-BellSoft+33)
OpenJDK 64-Bit Server VM (build 13-BellSoft+33, mixed mode, sharing)
Con Eclipse, no tengo ningún error. Con javac, tengo el error :
A.java:13: error: incompatible types: List<A<CAP#1>.C> cannot be converted to List<A<? extends B>.C>
List<A<? extends B>.C> y = x.list;
^
where CAP#1 is a fresh type-variable:
CAP#1 extends B from capture of ? extends B
El compilador de Eclipse debe mostrar un error de compilación, como javac
lo hace. Ver Eclipse bug 539105 .
javac
comportamiento es correcta y está alineado con los JLS :
Y si una clase genérica
C<T>
tiene una clase de miembro no genéricoD
, entonces el tipo de miembroC<String>.D
es un tipo parametrizado, a pesar de que la claseD
no es genérica.
Por lo tanto, a pesar de que la clase interna C
no es genérica, el:
A<? extends B>.C
es un tipo parametrizado , donde el parámetro de tipo de A
es un desconocido subtipo de B
. Por lo tanto, todas las normas sobre los genéricos se aplican a C
tan bien en este contexto.
Por lo tanto, para eliminar el error del compilador, el tipo de y
puede ser declarado de la siguiente manera:
List<? extends A<? extends B>.C> y = x.list;
Pero hay que tener en cuenta que esto no permitirá añadir elementos a la lista y
(ver PECS ).
Si suena complicado, trate de pensar en ello en el alcance de un ejemplo simplificado:
List<Integer> l1 = new ArrayList<>();
List<Number > l2 = l1; // Error: incompatible types...
List<? extends Number> l3 = l1; // OK
Detalles adicionales:
El ejemplo de la pregunta puede ser minimizado a:
class A<T> {
class C {}
List<C> l1 = null;
List<A<?>.C> l2 = l1; // Error: incompatible types...
List<? extends A<?>.C> l3 = l1; // OK
}
List<A<?>.C>
es una lista de C
de A
de tipo desconocido; C
de arbitraria A
puede ser añadido:
class A<T> {
class C {}
C c = new C();
void foo(List<A<?>.C> list) {
list.add(new A<String>().c);
list.add(new A<Number>().c);
}
}
Ver también: