Whats new? | Login | Parceiros
Cadastre-se | Atendimento | RSS
+ Java:
artigos   |   vídeos   |    cursos   |    mais

Um passeio pelo Java 5 - Generics - Parte II

No artigo passado falei sobre: laço for melhorado, Autoboxing/Unboxing, enumerações (Enums), métodos com número de argumentos...

CHRISTIAN CLEBER MASDEVAL BRAZ
Christian Cleber Masdeval Braz (masdeval@yahoo.com.br) é bacharel em Ciência da Computação pela UFMS. Em 2004 concluiu o mestrado, também naquela instituição, na área de inteligência artificial e problemas combinatoriais difíceis. Funcionário da Dat...


Ver space do autor


Estatísticas:
Visualizações:
14283
Favoritado:
 8 vez(es)
Conteúdo:
Didática:
Utilidade:
0 2
votos: 2

Serviços:



Um passeio pelo Java 5

Parte II – Generics

 

Interoperabilidade com Código Legado

Considere a atribuição:

 

Collection c = new ArrayList();

 

Ela é permitida para garantir um certo grau de compatibilidade entre as versões da linguagem (afinal todo código Java escrito até hoje foi sem generics). Quando um tipo genérico como Collection é utilizado sem parâmetro de tipo é chamado um raw type. Porém, o uso deste artifício deve ser feito com muito cuidado!

 

Vejamos seus desdobramentos na linha abaixo:

 

c.add(new Integer(10)); //unchecked warning

 

O compilador não acusará erro mas emitirá um aviso. O aviso é necessário porque o compilador não é capaz de garantir a corretude do resultado. Mas a possibilidade de se incluir um inteiro numa lista de strings não deveria ser um erro? Teoricamente sim, mas, na prática, se é necessário que código genérico opere com código legado isto deve ser permitido. Vejamos outro exemplo:

 

ArrayList fl = c; //unchecked warning

Dica

Dica 2. Quando usar métodos genéricos ou wildcards?

Use wildcard quando na assinatura do método o tipo paramétrico aparecer somente uma vez, ou seja, não há interdependência de tipos (nem de retorno, nem de argumentos).

public boolean containsAll(Collection c)
public boolean containsAll(Collection c)

Qual a melhor opção para os métodos acima? O parâmetro T está sendo usado neste caso apenas para prover polimorfismo e permitir que o método seja invocado com tipos diferentes. Use wildcards quando precisar representar tipos flexíveis, que é o que pretende-se expressar aqui.

“Métodos genéricos permitem que os tipos paramétricos sejam utilizados para expressar dependências entre tipos de argumentos e/ou seu tipo de retorno. Se não existe tal dependência um método genérico não deve ser empregado.”

public T getSomething (T something) {…}
public static void copy (List dest, Listextends T> src) {…}

Estes métodos são exemplos de dependência do parâmetro de tipo. No primeiro, a dependência está no tipo de retorno (sim, o tipo de retorno pode ser variável !!) e no segundo a lista de origem (src) deve ser de algum subtipo da lista de destino (dest).


O compilador não consegue garantir que c contenha apenas objetos Float e emite novamente um aviso. Fica a cargo do programador satisfazer os contratos estabelecidos e assim, por exemplo, prezar para que contenha uma coleção de números.

 

Chamar código legado a partir de código genérico é intrinsecamente perigoso! Uma vez que você mistura código genérico com código não genérico todas as garantias de segurança que usualmente um código genérico provê são perdidas. Entretanto, ainda assim é melhor do que não usar código genérico algum.

 

Casts, Arrays e Literais de Classe

 

O que o seguinte código irá imprimir?

 

List l1 = new ArrayList();

List l2 = new ArrayList();

System.out.println(l1.getClass() == l2.getClass());

 

Você pode ficar tentado a dizer que será false mas na verdade é true. Todas as instâncias de uma classe genérica compartilham a mesma meta-classe (ou run-time class) independentemente dos valores atuais dos seus parâmetros de tipo (tal como ocorre com classes não genéricas). Uma conseqüência disso é que em variáveis e métodos estáticos, por serem compartilhados por todas as instâncias, não pode haver referências a parâmetros de tipo.

 

Uma outra implicação é que não faz sentido perguntar para uma instância se esta é uma instância de um tipo particular. O código:

 

Collection cs = new ArrayList();

if(cs instanceof Collection) {…} //ilegal!!

 

é ilegal, bem como fazer os casts

 

Collection str = (Collection) cs; // unchecked warning

 

ou

 

T badCast(T t, Object o) {return (T) o;} //unchecked warning

 

Variáveis de tipo não existem em tempo de execução. Em ambos os casos o compilador não pode garantir a conversão.

 

Não é permitida, por questões de segurança, a criação de arrays de tipos genéricos. Então as seguintes tentativas não são válidas

 

List[] L1 = new List[10]; //Erro – tentativa de criar um array de genéricos

List[] L2 = new List[10]; //Erro – tipos incompatíveis

List[] L3 = new List[10]; //Erro – tentativa de criar um array de genéricos

 

A única opção possível é a criação de (unbounded) wildcard arrays. Por exemplo

 

List[] lsa = new List[10]; //OK - array de unbounded wildcard

lsa[0] = new ArrayList();

lsa[1] = new LinkedList();

List li = new ArrayList();

li.add(new Integer(10));

lsa[3] = li;

Integer xx = (Integer) lsa[3].get(0); //É necessário um cast

Dica

Dica

Generics são implementados pelo compilador através de um mecanismo de conversão chamado erasure. Pode-se pensar neste como uma tradução source-to-source onde, basicamente, todas as informações de tipos genéricos são “apagadas“. Toda informação de tipo entre <> é removida, então, por exemplo, List é convertido para List. Os outros usos dos parâmetros de tipo dentro do código são substituídos (geralmente) por Object. Por fim, sempre onde o código resultante não estiver com o tipo correto um cast para o tipo apropriado é inserido.

Esse funcionamento explica porque uma classe genérica é compartilhada por todas as suas instâncias e também porque operações de verificação ou conversão de tipos genéricos não funcionam.

 

A classe java.lang.Class é genérica agora e é um bom exemplo de aplicação de generics além de coleções. Por exemplo, o tipo String.class é Class e o tipo Calendar.class é Class. Um dos principais benefícios é a utilização do literal de classe como fábrica de objetos e com a versão genérica isto ficou mais seguro pois pode-se obter um tipo preciso. Para entender melhor a diferença compare as duas versões abaixo:

 

Collection emps = sqlUtility.select(EmpInfo.class, “select * from emps”);

public static Collection select(Class c, String query)

{

Collection result = new ArrayList();

/* Executa a consulta */

for(/* Itera no resultset */)

{

Object item = c.newInstance(); //Retorna um Object

/* Utilize reflexao para setar os atributos do objeto baseado nos registros do banco*/

result.add(item); //Povoa a coleção com Objects

}

return result;

}

Collection emps = sqlUtility.select(EmpInfo.class, “select * from emps”);

public static Collection select(Class c, String query)

{

Collection result = new ArrayList();

/* Executa a consulta */

for(/* Itera no resultset */)

{

T item = c.newInstance(); //Retorna um EmpInfo

/* Utilize reflexao para setar os atributos do objeto baseado nos registros do banco*/

result.add(item); // Povoa a coleção com o tipo específico

}

return result;

}





Participe! Inclua um comentário
[Fechar]

Este post é fechado - você precisa ter acesso ao post para incluir um comentário.


Nenhum comentário foi postado - seja o primeiro a comentar ;-)



 


[Fechar]
Este post está disponível para assinantes da Java Magazine ou para quem possui Créditos DevMedia.

  Conheça os planos de créditos DevMedia e visualize esse post agora mesmo!

Plano conveniência – Neste plano este post custa R$ 0,00 (Compre agora)
Esse plano permite que você compre somente um post, pagando por ele seu preço sem desconto.

Plano ocasional: Aqui este post custa: R$ -1,00 (assinante) ou R$ -1,00 (não-assinante)
Este plano é ideal para quem tem interesse em mais de um post. Você compra um mínimo de R$ 50,00 em créditos e ganha, em média, 50% de desconto no preço do post. Compre Créditos agora!

Assinatura de Créditos (Plano econômico) – Aqui este post custa R$ -1,00
Este plano é ideal para quem tem interesse em muitos posts. Com esse plano você compra R$ 180,00 em créditos e ganha, em média, 80% de desconto no preço do post. Assine este plano agora!

> Saiba mais sobre o Sistema de Créditos DevMedia
DevMedia Group   www.devmedia.com.br   |   www.javafree.org   |   www.mrbool.com
2010 - Todos os Direitos Reservados a DevMedia Group - (21) 3382-5038