java - parameter - Collections.emptyList() devuelve una lista<Object>?
java generic type inheritance (3)
Tengo algunos problemas para navegar la regla de Java para inferir parámetros de tipo genérico. Considere la siguiente clase, que tiene un parámetro de lista opcional:
import java.util.Collections;
import java.util.List;
public class Person {
private String name;
private List<String> nicknames;
public Person(String name) {
this(name,Collections.emptyList());
}
public Person(String name,List<String> nicknames) {
this.name = name;
this.nicknames = nicknames;
}
}
Mi compilador de Java da el siguiente error:
Person.java:9: The constructor Person(String, List<Object>) is undefined
Pero Collections.emptyList()
devuelve el tipo <T> List<T>
, no List<Object>
. Agregar un reparto no ayuda
public Person(String name) {
this(name,(List<String>)Collections.emptyList());
}
rendimientos
Person.java:9: inconvertible types
Usando EMPTY_LIST
lugar de emptyList()
public Person(String name) {
this(name,Collections.EMPTY_LIST);
}
rendimientos
Person.java:9: warning: [unchecked] unchecked conversion
Mientras que el siguiente cambio hace desaparecer el error:
public Person(String name) {
this.name = name;
this.nicknames = Collections.emptyList();
}
¿Alguien puede explicar a qué regla de verificación de tipo me estoy enfrentando aquí y cuál es la mejor manera de solucionarlo? En este ejemplo, el ejemplo del código final es satisfactorio, pero con clases más grandes, me gustaría poder escribir métodos siguiendo este patrón de "parámetro opcional" sin duplicar el código.
Para crédito adicional: ¿cuándo es apropiado usar EMPTY_LIST
en lugar de emptyList()
?
El método emptyList tiene esta firma:
public static final <T> List<T> emptyList()
Que <T>
antes de la lista de palabras significa que infiere el valor del parámetro genérico T del tipo de variable al que se asigna el resultado. Así que en este caso:
List<String> stringList = Collections.emptyList();
A continuación, se hace referencia explícita al valor de retorno mediante una variable de tipo List<String>
, de modo que el compilador pueda averiguarlo. En este caso:
setList(Collections.emptyList());
No hay una variable de retorno explícita para que el compilador la utilice para averiguar el tipo genérico, por lo que su valor predeterminado es Object
.
El problema que está encontrando es que a pesar de que el método emptyList()
devuelve la List<T>
, no le ha proporcionado el tipo, por lo que el valor predeterminado es devolver la List<Object>
. Puede suministrar el parámetro de tipo y hacer que su código se comporte como se espera, de la siguiente manera:
public Person(String name) {
this(name,Collections.<String>emptyList());
}
Ahora, cuando está realizando una asignación directa, el compilador puede averiguar los parámetros de tipo genérico para usted. Se llama inferencia de tipos. Por ejemplo, si hiciste esto:
public Person(String name) {
List<String> emptyList = Collections.emptyList();
this(name, emptyList);
}
entonces la llamada a emptyList()
devolvería correctamente una List<String>
.
Quieres usar:
Collections.<String>emptyList();
Si observa la fuente de la lista vacía, ¿ve que en realidad solo hace una
return (List<T>)EMPTY_LIST;