Tengo 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 en EMPTY_LIST
lugar deemptyList()
public Person(String name) {
this(name,Collections.EMPTY_LIST);
}
rendimientos
Person.java:9: warning: [unchecked] unchecked conversion
Mientras que el siguiente cambio hace que el error desaparezca:
public Person(String name) {
this.name = name;
this.nicknames = Collections.emptyList();
}
¿Alguien puede explicar con qué regla de verificación de tipo me estoy enfrentando aquí y la mejor manera de evitarlo? 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()
?
fuente
Respuestas:
El problema que está encontrando es que a pesar de que el método
emptyList()
regresaList<T>
, no lo ha proporcionado con el tipo, por lo que el valor predeterminado es regresarList<Object>
. Puede proporcionar el parámetro de tipo y hacer que su código se comporte como se espera, así:Ahora, cuando realiza una asignación directa, el compilador puede descubrir los parámetros de tipo genérico por usted. Se llama inferencia de tipos. Por ejemplo, si hiciste esto:
entonces la
emptyList()
llamada devolvería correctamente aList<String>
.fuente
this
debe ser la primera instrucción en el constructor.Quieres usar:
Si observa la fuente de qué emptyList, verá que en realidad solo hace un
fuente
El método emptyList tiene esta firma:
Que
<T>
antes de la palabra Lista significa que infiere el valor del parámetro genérico T del tipo de variable al que se asigna el resultado. Entonces en este caso:El valor de retorno es referenciado explícitamente por una variable de tipo
List<String>
, para que el compilador pueda resolverlo. En este caso:No hay una variable de retorno explícita para que el compilador la use para descubrir el tipo genérico, por lo que su valor predeterminado es
Object
.fuente