Por que não consigo passar explicitamente o argumento de tipo para um método Java genérico?

StackOverflow https://stackoverflow.com/questions/24991

  •  09-06-2019
  •  | 
  •  

Pergunta

Eu defini uma função Java:

static <T> List<T> createEmptyList() {
    return new ArrayList<T>();
}

Uma maneira de chamá-lo é assim:

List<Integer> myList = createEmptyList(); // Compiles

Por que não posso chamá-lo passando explicitamente o argumento do tipo genérico?:

Object myObject = createEmtpyList<Integer>(); // Doesn't compile. Why?

eu recebo o erro Illegal start of expression do compilador.

Foi útil?

Solução

Quando o compilador java não consegue inferir o tipo de parâmetro por si só para um método estático, você sempre pode passá-lo usando o nome completo do método qualificado:Aula .<Tipo> método();

Object list = Collections.<String> emptyList();

Outras dicas

Você pode, se passar o tipo como parâmetro do método.

static <T> List<T> createEmptyList( Class<T> type ) {
  return new ArrayList<T>();
}

@Test
public void createStringList() {
  List<String> stringList = createEmptyList( String.class );
}

Os métodos não podem ser genéricos da mesma maneira que um tipo, então a única opção para um método com um tipo de retorno genérico digitado dinamicamente - ufa, isso é demais :-) - é passar o tipo como um argumento.

Para um FAQ verdadeiramente excelente sobre genéricos Java, veja as perguntas frequentes sobre genéricos de Angelika Langer.

.
.

Seguir:

Não faria sentido neste contexto usar o argumento array como em Collection.toArray( T[] ).A única razão pela qual uma matriz é usada é porque a mesma matriz (pré-alocada) é usada para conter os resultados (se a matriz for grande o suficiente para caber todos eles).Isso economiza na alocação de um novo array em tempo de execução o tempo todo.

No entanto, para fins educacionais, se você quiser usar a digitação de array, a sintaxe é muito semelhante:

static <T> List<T> createEmptyList( T[] array ) {
  return new ArrayList<T>();
}

@Test
public void testThing() {
  List<Integer> integerList = createEmptyList( new Integer[ 1 ] );
}

Já faz algum tempo que não pesquisei essas partes do Java, mas...

O motivo pelo qual você não pode fazer isso provavelmente foi uma escolha de design dos desenvolvedores da linguagem.Ainda assim, devido ao tipo apagamento empregado por Java, as informações genéricas são eliminadas em tempo de compilação de qualquer maneira, portanto, no seu exemplo, ele criaria exatamente o mesmo código de bytes, independentemente de você ter o parâmetro de tipo ou não.

@pauldoo Sim, você está certo.É um dos pontos fracos dos genéricos java imho.

Em resposta à Cheekysoft, gostaria de propor também ver como isso é feito pelo próprio pessoal de Java, como T[] AbstractCollection#toArray(T[]a).Acho a versão do Cheekysofts superior, mas a do Java tem a vantagem da familiaridade.

Editar:Link adicionado.Reeditar:Encontrei um bug no SO :)


Acompanhamento no Cheekysoft:Bem, como é uma lista de algum tipo que deve ser retornada, o exemplo correspondente deve ser algo como:

static <T> List<T> createEmptyList( List<T> a ) {
  return new ArrayList<T>();
}

Mas sim, passar o objeto de classe é claramente o melhor.Meu único argumento é o da familiaridade, e neste exato caso não vale muito (na verdade, é ruim).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top