JAVA: Criação de Array Genérico

IcePicK

Power Member
Uma das questões mais pertinentes em relação aos tipos genéricos do Java é a criação de arrays.

Por exemplo, como criar um array "nativo" partindo de uma colecção?

Código:
public static <T> T[] toArray(final Collection<T> c);

Uma das implementações possiveis deste método é:

Código:
public static <T> T[] toArray(final Collection<T> c) {
	return c.toArray((T[]) Array.newInstance(c.iterator().next().getClass(), 0));
}

Mas este método só funciona se:
  • c tem pelo menos um elemento
  • o primeiro elemento de c é mesmo do tipo T e não um sub-tipo

Quais as vossas soluções para este problema?
 
o primeiro elemento de c é mesmo do tipo T e não um sub-tipo

O que queres dizer com sub-tipos? Quando crias uma classe genérica <T> ou <K,V> tens que assumir que todos os dados são tratados uniformemente. Se posteriormente usares essa estrutura para Strings, para as funções funcionarem convenientemente devem usar o mesmos tipos. Logo, penso que não existem soluções para esse problema. Tens que tratar todos os tipos de dados como <T>.

Nao percebi bem a duvida, portanto, espero ter ajudado.

Cumps ;).
 
O que queres dizer com sub-tipos? Quando crias uma classe genérica <T> ou <K,V> tens que assumir que todos os dados são tratados uniformemente. Se posteriormente usares essa estrutura para Strings, para as funções funcionarem convenientemente devem usar o mesmos tipos. Logo, penso que não existem soluções para esse problema. Tens que tratar todos os tipos de dados como <T>.

Nao percebi bem a duvida, portanto, espero ter ajudado.

Cumps ;).

Quando digo que não pode ser um sub-tipo é porque esta implementação utiliza o primeiro elemento para obter o tipo para o novo array (c.iterator().next().getClass()). Portanto, se o primero elemento for X (sub-tipo de T) vai ser criado um X[] resultando mais tarde numa ClassCastException.

eu uso c.toArray(new <Tipo do C>[c.size()])

Pois, eu também faço assim quando sei o tipo. Aqui não sabemos o tipo.

Uma solução possivel mas menos transparente era:

Código:
public static <T> T[] toArray(final Collection<T> c, Class<T[]> clazz) {
	return c.toArray((T[]) Array.newInstance(clazz, 0));
}

No entanto fica menos "elegante" para os clientes.
 
E que tal percorrer todos os elementos e verificar qual o que tem a hierarquia mais elevada? Se a colecção tiver dimensão zero retornas Objecto. Sinceramente parece-me muito esforço para nada.

Edit: Mas estás a tentar resolver algum problema concreto? Se não sabes os tipos de objectos da colecção depois de converteres para array continuas sem saber os tipos em tempo de compilação dai eu não perceber qual o objectivo.
 
Última edição:
E que tal percorrer todos os elementos e verificar qual o que tem a hierarquia mais elevada? Se a colecção tiver dimensão zero retornas Objecto. Sinceramente parece-me muito esforço para nada.

Edit: Mas estás a tentar resolver algum problema concreto? Se não sabes os tipos de objectos da colecção depois de converteres para array continuas sem saber os tipos em tempo de compilação dai eu não perceber qual o objectivo.

Sim, estou a resolver um problema em concreto e que nem conseguia explicar aqui.

As classes clientes sabem quais os tipos com que estão a trabalhar. Só queria fazer as coisas transparentes para os clientes.

Entretanto já resolvi o problema para este caso em especifico ficando a questão geral em aberto.
 
Código:
public static <T> T[] toArray(final Collection<T> c) {
	return c.toArray((T[]) new Object[c.size()]);
}

Se fizeres...
Código:
ArrayList<String> s = new ArrayList<String>();

String [] a = toArray(s);
com a tua implementação vai dar uma ClassCastException pois estas a fazer um cast implícito de Object[] para String[].
 
Passado tanto tempo depois de ter tentado contornar o erasure das mais diversas maneiras, esta thread vem-me lembrar o porquê de ter parado. Devia ter aprendido a lição melhor.
 
Sim, aquele cast não faz qualquer tipo de sentido. De qualquer forma, arrays e tipos genéricos não combinam muito bem. Provavelmente, é algo que deverá ser melhorado na próxima versão do Java. Aliás, basta pesquisar por "java erase erasure" no Google, que aparecem bastantes resultados.

Para concluir, já aqui colocaste várias possíveis soluções para o problema; poderão não ser as mais elegantes, mas isto é uma "limitação" do Java e, como tal, não tens grandes alternativas. Podes sempre mudar para .NET (C#) que não padece dos mesmos problemas, apesar de eu achar que o problema em questão não é particularmente relevante, pelas razões que já foram mencionadas num post mais acima.
 
Última edição:
Back
Topo