useful parameter method generic example are java generics types wildcard

parameter - java generics method



Generics, Type Parameters and Wildcards (1)

Estoy tratando de entender los genéricos de Java y parecen extremadamente difíciles de entender. Por ejemplo, esto está bien ...

public class Main { public static void main(String[] args) { List<?> list = null; method(list); } public static <T> void method(List<T> list) { } }

... como es esto ...

public class Main { public static void main(String[] args) { List<List<?>> list = null; method(list); } public static <T> void method(List<T> list) { } }

... y esto ...

public class Main { public static void main(String[] args) { List<List<List<?>>> list = null; method(list); } public static <T> void method(List<List<T>> list) { } }

... pero esto no compila:

public class Main { public static void main(String[] args) { List<List<?>> list = null; method(list); } public static <T> void method(List<List<T>> list) { } }

¿Alguien puede explicar lo que está pasando en un lenguaje simple?


Lo principal para entender con tipos genéricos es que no son covariantes.

Entonces, mientras puedes hacer esto:

final String string = "string"; final Object object = string;

Lo siguiente no compilará:

final List<String> strings = ... final List<Object> objects = strings;

Esto es para evitar las situaciones en las que elude los tipos genéricos:

final List<String> strings = ... final List<Object> objects = strings; objects.add(1); final String string = strings.get(0); <-- oops

Por lo tanto, repasando tus ejemplos uno por uno

1

Su método genérico toma una List<T> , pasa en una List<?> ; que es (esencialmente) una List<Object> . T se puede asignar al tipo de Object y el compilador está contento.

2

Su método genérico es el mismo, pasa una List<List<?>> . T se puede asignar al tipo List<?> Y el compilador está feliz de nuevo.

3

Esto es básicamente lo mismo que 2 con otro nivel de anidación. T sigue siendo el tipo de List<?> .

4

Aquí es donde va un poco en forma de pera, y donde entra mi punto de arriba.

Su método genérico toma una List<List<T>> . Usted pasa en una List<List<?>> . Ahora, como los tipos genéricos no son covariantes, List<?> No se puede asignar a una List<T> .

El error real del compilador (Java 8) es:

required: java.util.List<java.util.List<T>> found: java.util.List<java.util.List<?>> reason: no se puede inferir type-variable (s) T (argumento no coincide; java.util.List<java.util.List<?>> no se puede convertir a java.util.List<java.util.List<T>> )

Básicamente, el compilador le dice que no puede encontrar una T para asignar debido a que tiene que inferir el tipo de List<T> anidado en la lista externa.

Veamos esto con un poco más de detalle:

List<?> Es una List de algún tipo desconocido , podría ser una List<Integer> o una List<String> ; podemos get como Object , pero no podemos add . Porque de lo contrario nos encontramos con el problema de covarianza que mencioné.

List<List<?>> es una List de List de algún tipo desconocido; podría ser una List<List<Integer>> o una List<List<String>> . En el caso 1 , fue posible asignar T a Object y simplemente no permitir add operaciones en la lista de comodines. En el caso 4 esto no se puede hacer, principalmente porque no hay una construcción de genéricos para evitar add a la List externa.

Si el compilador asignara T a Object en el segundo caso, sería posible algo como lo siguiente:

final List<List<Integer>> list = ... final List<List<?>> wildcard = list; wildcard.add(Arrays.asList("oops"));

Entonces, debido a la covarianza, no es posible asignar una List<List<Integer>> a ninguna otra List genérica de forma segura.