Estou com problemas para navegar na regra do Java para inferir parâmetros de tipo genérico. Considere a seguinte classe, que possui um 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;
}
}
Meu compilador Java fornece o seguinte erro:
Person.java:9: The constructor Person(String, List<Object>) is undefined
Mas Collections.emptyList()
retorna tipo <T> List<T>
, não List<Object>
. Adicionar um elenco não ajuda
public Person(String name) {
this(name,(List<String>)Collections.emptyList());
}
rendimentos
Person.java:9: inconvertible types
Usando em EMPTY_LIST
vez deemptyList()
public Person(String name) {
this(name,Collections.EMPTY_LIST);
}
rendimentos
Person.java:9: warning: [unchecked] unchecked conversion
Considerando que a seguinte alteração faz com que o erro desapareça:
public Person(String name) {
this.name = name;
this.nicknames = Collections.emptyList();
}
Alguém pode explicar qual regra de verificação de tipo estou enfrentando aqui e a melhor maneira de contornar isso? Neste exemplo, o exemplo de código final é satisfatório, mas com classes maiores, eu gostaria de poder escrever métodos seguindo esse padrão de "parâmetro opcional" sem duplicar o código.
Para crédito extra: quando é apropriado usar EMPTY_LIST
ao invés de emptyList()
?
fonte
Respostas:
O problema que você está enfrentando é que, embora o método
emptyList()
retorneList<T>
, você não forneceu o tipo, então o padrão é retornarList<Object>
. Você pode fornecer o parâmetro type e fazer com que seu código se comporte conforme o esperado, assim:Agora, quando você está realizando uma tarefa direta, o compilador pode descobrir os parâmetros de tipo genérico para você. É chamado de inferência de tipo. Por exemplo, se você fez isso:
a
emptyList()
chamada retornaria corretamente aList<String>
.fonte
this
deve ser a primeira instrução no construtor.Você quer usar:
Se você procurar na fonte o que emptyList você vê, ele realmente faz um
fonte
o método emptyList possui esta assinatura:
Que
<T>
antes de os meios lista de palavras que infere o valor do parâmetro genérico T do tipo de variável, o resultado é atribuído. Então, neste caso:O valor de retorno é então referenciado explicitamente por uma variável do tipo
List<String>
, para que o compilador possa descobrir isso. Nesse caso:Não há uma variável de retorno explícita para o compilador usar para descobrir o tipo genérico; portanto, o padrão é
Object
.fonte