terça-feira, abril 03, 2007

Genérics no Java (apartir do 5)

[update]
Pesso perdão a todos que leram o post antes deste update pois haviam 2 erros graves. O primeiro era a grafia da palavra generics como ressaltou um leitor nos comentários.
O segundo era que eu esqueci de trocar os sinais de < e > pelos seus respectivos códigos HTML numéricos.
Agora sim o post está funcionando :D e coloquei nos links abaixo os códigos usados para ilustrar os exemplos.
Desculpa aí pessoal, qualquer coisa comente aí!

http://geocities.yahoo.com.br/sadbuttruebr/blog/
exemplos_java/Caixa.java

http://geocities.yahoo.com.br/sadbuttruebr/blog/
exemplos_java/CaixaGenerica.java

[/update]


Dae pessoal, estamos aqui para mais um post de (in)utilidade pública e que já deve ter sido publicado em n sítios/blogs por aí na rede bem melhor redigido do que o meu :P, masss o meu é melhor! Hehehe ao menos eu e a minha mãe achamos... :P


Não sei como vivemos tanto tempo sem os tipos genéricos no Java. Que trabalho insano dava fazer certas coisas além de estarmos à mercê de erros bizarros. Vamos ilustrar a dor de cabeça com uma classe simples chamada Caixa.java que tem dois métodos: colocarNaCaixa e mostrarConteudo. O que a classe faz nada mais é do que criar uma caixa que recebe um objeto de qualquer tipo e mostra que tipo é o objeto colocado lá dentro e seu valor.

Vamos ao que é good, código!

public class Caixa {

private Object objeto;

public void colocarNaCaixa(Object objeto) {
this.objeto = objeto;
}

public Object mostrarConteudo() {
return objeto;
}

public static void main(String[] args) {
Caixa cxInteiros = new Caixa();

cxInteiros.colocarNaCaixa(10);

int i = (Integer)cxInteiros
.mostrarConteudo();

System.out.println("Tipo do objeto posto
na caixa: " + cxInteiros
.mostrarConteudo().getClass()
.getName());
System.out.println("Valor do objeto posto
na caixa: " + i);

Caixa cxStrings = new Caixa();

cxStrings.colocarNaCaixa("Olá genéricos");

String valor = (String)cxStrings
.mostrarConteudo();

System.out.println("Tipo do objeto posto
na caixa: " + cxStrings.mostrarConteudo()
.getClass().getName());
System.out.println("Valor do objeto posto
na caixa: " + valor);
}
}

Notem o seguinte, NADA impede de eu colocar qualquer tipo de conteúdo na minha caixa, a não ser uma convenção fraca explícita no código, algo como:
//Caixa só para inteiros
Caixa cx = new Caixa();

Patético... fora os inúmeros casts inúteis que temos:

Caixa cxInteiros = new Caixa();
cxInteiros.colocarNaCaixa(10);
int i = (Integer)cxInteiros.mostrarConteudo();

Bom como solucionar esse tipo de coisa?
Resposta: GENERICS!

O que é um objeto/método genérico?
É uma classe/método que só aceita um certo tipo de parâmetro... ta deixemos de blablabla e vamos ao código disto tudo:

public class CaixaGenerica<T> { //Ai já diremos que
//tipo de dado
//esperar.

private T objeto; //T é do mesmo tipo do T que
//especificamos quando instan-
//ciamos o objeto.

public void colocarNaCaixa(T objeto) {
this.objeto = objeto;
}

public T mostrarConteudo() {
return objeto;
}

public static void main(String[] args) {
//Instanciamos uma caixa só para inteiros
CaixaGenerica<Integer> cxInteiros =
new CaixaGenerica<Integer>();

cxInteiros.colocarNaCaixa(10);

/*
* O melhor, sem CAST! O compilador sabe que
* tipo de dados tem na caixa.
*/
int i = cxInteiros.mostrarConteudo();

System.out.println("Tipo do objeto posto na
caixa: " + cxInteiros.mostrarConteudo().getClass()
.getName()
);
System.out.println("Valor do objeto posto
na caixa: " + i);

CaixaGenerica<String> cxPalavras =
new CaixaGenerica<String>();

cxPalavras.colocarNaCaixa("Java Generics é
o bixo!");

String palavra = cxPalavras.mostrarConteudo();

System.out.println("Tipo do objeto posto
na caixa: " + cxPalavras.mostrarConteudo().getClass()
.getName());
System.out.println("Valor do objeto posto
na caixa: " + palavra );
}
}

Não tem como instanciarmos uma caixa de um gênero e tentarmos atribuir um valor de outro a caixa... dará erro ao tentarmos compilar a classe.

Agora pense em todo tipo de coleção que você já usou antes dos generics que agora lhe
poupariam algum tempo sem casts e sem erros...

Isso é post de coisa antigaaaaaa, só para encher lingüiça mesmo, mas me espanta gente que se diz desenvolvedor Java e não conhece generics.

Até a próxima e já sabe né... comenta aí!

3 comentários:

Anônimo disse...

A intenção foi legal, mas escrever genérics foi tosco.... esse acento não deveria estar ali.

asclows disse...

Jean, seu post apesar de você achar uma bobeira, iniciantes como eu podem precisar dele mesmo que seja apenas uma vez, então pode ir desabafando mais bobeira aqui no seu blog.

Pelo que você postou generics fica como somente uma restrição de tipo, mas ainda não entendi, acho que fiquei confuso no seguinte:

"T é do mesmo tipo do T que especificamos quando instanciamos o objeto".

Onde tá esta especificação?

Você instanciou seu objeto assim..

CaixaGenerica cxInteiros = new CaixaGenerica();

Onde está a definição do tipo do atributo?

Se é na própria classe CaixaGenerica, por exemplo atributo do tipo String, lógicamente não seria possível atribuição de outro tipo de objeto a ele isso já é default da linguagem.

Fiquei confuso cara. Generics é somente o fato de não precisar do casting ao atribuir o objeto retornado pelo método?

Não seria isso um Unboxing? Sua classe CaixaGenerica não estaria servindo de Wrapper para o atributo? Ou estou misturando tudo?

Jean Michel disse...

Cara pesso desculpas, o post contia um erro grave... pesso que vc leia novamente, baixe os fonts e qualquer problema volte a me perguntar que terei prazer em lhe responder! :P

Abraço.