Você está na página 1de 26

Java

com

Programao em

50 .

J2SE

Tipos genricos

Helder da Rocha
Julho 2005

O que so os Genricos?
Recurso introduzido no Java 5.0
Sintaxe que permite restringir os tipos de dados aceitos por referncias genricas Permite verificao de tipo em tempo de compilao!

Exemplo: colees
Permitem agrupar objetos de diferentes tipos, devido sua interface genrica (baseada em Object)
interface List { public void add(Object item); public Object get(int index); public Iterator iterator(); ... } interface Iterator { public Object next(); ... }

Vantagem: aceita qualquer tipo Desvantagem: retorna tipo genrico e requer downcasting que s verificado em tempo de execuo

O Problema
Antes dos genricos, era preciso fazer coero (cast) para usar os dados recuperados de colees
Galinha rosalinda Object addParameter Object nextReturn
Heap

Fazenda fazenda = Fazenda.getInstance(); Galinha g1 = new Galinha(Chocagilda"); Galinha g2 = new Galinha(Cocotalva"); // galinhas entram no galinheiro g1.entrarNoGalinheiro(fazenda.getGalinheiro()); g2.entrarNoGalinheiro(fazenda.getGalinheiro()); Fazendeiro ze = new Fazendeiro(fazenda); Iterator galinhas = ze.pegarGalinhas(); while(galinhas.hasNext()) { Galinha galinha = (Galinha) galinhas.next(); }
class Galinha { public void entrarNoGalinheiro(List galinheiro) { galinheiro.add(this); } }

Galinha

Referncias so verificadas em tempo de compilao


class Fazenda { ... private List galinheiro = new ArrayList(); public List getGalinheiro() { return galinheiro; } }

O Problema (2)
E havia o risco do programador cometer um erro (j que no h verificao de tipos de objeto na compilao)
Raposa gargamel Object addParameter Object nextReturn
Heap

Raposa

g1.entrarNoGalinheiro(fazenda.getGalinheiro()); g2.entrarNoGalinheiro(fazenda.getGalinheiro()); ... // entra uma raposa!!! Raposa galius = new Raposa(Galius"); galius.assaltar (fazenda.getGalinheiro()); Fazendeiro ze = new Fazendeiro(fazenda); Iterator galinhas = ze.pegarGalinhas(); while(galinhas.hasNext()) { Galinha galinha = (Galinha) galinhas.next(); }

Referncias esto corretas: Trata-se de um Object! Mas no d para fazer cast de para uma referncia Galinha

class Raposa { public void assaltar(List lugar) { lugar.add(this); } }

FALHA! H uma raposa no meio das galinhas


[java] Exception in thread "main" java.lang.ClassCastException: Raposa

Correto! List tem add(Object) e Raposa um Object


4

Soluo sem usar genricos


Typesafe collection: padro de design
Apenas Galinhas so aceitas no galinheiro Para recuperar objetos, no necessrio usar cast! Mas Galinheiro no List, import java.util.*; public class GalinhaIterator E GalinhaIterator no Iterator private Iterator iterator;

import java.util.*; public class Galinheiro { private List galinhas; public Galinheiro(List list) { galinhas = list; } public GalinhaIterator iterator() { return new GalinhaIterator(galinhas.iterator()); } } public Galinha get(int idx) { No return (Galinha) galinhas.get(idx); } public void add(Galinha g) { galinhas.add(g); Galinheiro g = } new Galinheiro(new }

GalinhaIterator(Iterator it) { iterator = it; } public boolean hasNext() { return iterator.hasNext(); } public Galinha next() { return (Galinha)iterator.next(); }

compila! No requer cast!

ArrayList()); g.add(new Galinha("Frida")); // g.add(new Raposa(Galius)); Galinha frida = g.get(0);

Soluo com genricos (1)


Genricos permitem associar um tipo referncia
Restringe tipos permitidos ao passado como parmetro Permite verificao em tempo de compilao Parmetro de tipo
(type parameter)
class Fazenda { ... private List<Galinha> galinheiro = new ArrayList<Galinha>(); public List<Galinha> getGalinheiro() { return galinheiro; } }

Isto no um ArrayList de Object mas um ArrayList de Galinha

class Galinha { public void entrarNoGalinheiro(List<Galinha> galinheiro) { galinheiro.add(this); } }

Sintaxe bsica: TipoGenerico<TipoEspecifico>


6

Soluo com genricos (2)


Agora no precisamos mais do cast
Fazendeiro ze = new Fazendeiro(fazenda); Iterator<Galinha> galinhas = ze.pegarGalinhas(); while(galinhas.hasNext()) { Galinha galinha = galinhas.next(); // sem cast!!! }

Raposas tambm no entram mais


Precisam especificar tipo de lugar. O compilador avisa (warning) sobre uso de objetos inseguros:
[javac] Note: C:\usr\projects\Fragmentos.java uses unchecked or unsafe operations.

Conserta-se a Raposa:

Se a Raposa fosse esperta, declararia como <?>

class Raposa { public void assaltar(List<Object> lugar) { lugar.add(this); } }

O compilador acusa o erro!

mas mesmo assim no iria funcionar!

[javac] C:\usr\projects\Fragmentos.java:16: assaltar(java.util.List<java.lang.Object>) in Raposa cannot be applied to (java.util.List<Galinha>) 7

Nova interface java.util.Collection


public interface Collection<E> extends Iterable<E> { int size(); boolean isEmpty(); boolean contains(Object o); Iterator<E> iterator(); Object[] toArray(); <T> T[] toArray(T[] a); boolean add(E o); boolean remove(Object o); boolean containsAll(Collection<?> c); boolean addAll(Collection<? extends E> c); boolean removeAll(Collection<?> c); boolean retainAll(Collection<?> c); void clear(); }
8

Definio de genricos
Sintaxe de declarao: trecho de java.util.List
public interface List<E> extends Collection<E> { void add(E element); E get(int index); Iterator<E> iterator(); boolean addAll(Collection<? extends E> c); <T> T[] toArray(T[] a); }

Conveno: defina parmetros de tipo com uma letra, de caixaalta (ex: T de tipo, V de valor, E de Elemento, K de key)

Sintaxe de uso
List<Number> numeros = new ArrayList<Number>(); numeros.add(new Integer(5)); numeros.add(new Double(3.14)); Number pi = numeros.get(1); Collection<Long> longs = new HashSet<Long>(); longs.add(123L); longs.add(0xBABEL); boolean success = numeros.addAll(longs); Number[] dummy = {}; Number[] array = numeros.toArray(dummy); for (Number n: array) { System.out.println(n); } 9

Compilao de genricos
Uma declarao de tipo genrico compilada e gera uma classe Java comum, como outra qualquer
No um template! No h gerao especial de cdigo. Informao de generics serve para compilao e apagada no bytecode final No aumenta o tamanho do cdigo: veja os arquivos .class gerados e compare: so iguais aos anteriores.

Genricos funcionam como estruturas que aceitam parmetros em tempo de execuo


Uma razovel analogia comparar com a passagem de argumentos para parmetros em mtodos
10

Uma boa analogia


Em mtodos
Na declarao parmetros formais de valor descrevem os valores que o mtodo pode aceitar; Quando um mtodo chamado, os argumentos passados (valores e referncias) substituem os parmetros formais

Em genricos:
Na declarao, parmetros formais de tipo descrevem os tipos que o genrico pode representar; Quando um tipo genrico usado, os argumentos passados (tipos) substituem os parmetros formais
Mtodos
interface Exemplo { int metodo(int x); } Exemplo e = ... int r = e.metodo(5); Declarao

Tipos Genricos
class ArrayList<E> implements List<E> { ... } List<Integer> lista = new ArrayList<Integer>();
11

Uso

Hierarquia de subtipos
Se X um subtipo de Y, e G um tipo genrico, no verdade que G<X> um subtipo de G<Y> Exemplo: o cdigo abaixo ilegal
List<Galinha> galinhas = new ArrayList<Galinha>(); galinhas.add(new Galinha(Cocogilda")); List<Object> objetos = galinhas; // ILEGAL! Causa erro de compilao Galinha[] vg = { new Galinha(Cocogilda") }; Object[] vo = vg;

Ah, mas com arrays no seria!

Sim, mas arrays so imutveis; colees no!


Problemas poderiam acontecer se coleo crescesse
objetos.add(new Raposa()); // ok, pois Raposa Object Galinha gilda = galinhas.get(0); // Raposa fantasiada
12

Flexibilidade com curingas


De acordo com a regra anterior:
Collection<Object> no supertipo de Collection<Integer> Collection<Object> s aceita componentes Object!

O supertipo genrico verdadeiro Collection<?>


? o tipo desconhecido O tipo Collection<?> portanto uma Collection do desconhecido

Exemplo: o mtodo abaixo aceita colees que contenham qualquer tipo void printCollection(Collection<?> c) { ... } Limitaes
Colees de tipos desconhecidos podem ter seus componentes lidos, mas no pode receber novos componentes c.add(new Object()); // dentro do mtodo acima, ilegal Object obj = c.get(0); // legal, assumindo que o elemento 0 exista
13

Impondo limites
Pode-se impor limites aos curingas Limites superiores: <? extends T>
Aceita T e todos os seus descendentes Ex: se T for Collection, aceita List, Set, ArrayList, etc.

Limites inferiores: <? super T>


Aceita T e todos os seus ascendentes Ex: se T for ArrayList, aceita List, Collection, Object

Exemplo: mtodo que aceita qualquer Shape


class Canvas { public void drawAll(List<? extends Shape> shapes) { for(Shape s: shapes) { Shape s.draw(this); draw(Canvas) } } }
Circle draw(Canvas) Rectangle draw(Canvas)

14

Variaes
Tipos genricos podem receber mais argumentos Exemplo: Map<K, V>
K = key, V = value Exemplo:
Map<String, ? extends Employee>

usa uma String como chave para elementos que podem ser quaisquer subclasses de Employee
15

Mtodos genricos
Usados quando existem dependncias entre o tipo de retorno e os parmetros Exemplo de sintaxe
mods <T1, T2> tipoRetorno nome(Item<T1>, T2) {...}

Exemplo
declarao
static <T> void arrayToCollection(T[] arr, Collection<T> col) { for (T obj: arr) { col.add(obj); } }

uso
Collection<Number> nums = new ArrayList<Number>(); arrayToCollection(array, nums);
16

Curingas vs. mtodos genricos


Pode-se implementar com mtodos genricos o que se implementa com curingas. As implementaes abaixo so equivalentes
Collection original
interface Collection<E> { public boolean containsAll(Collection<?> c); public boolean addAll(Collection<? extends E> c); }

Collection implementada com mtodo genrico


interface Collection<E> { public <T> boolean containsAll(Collection<T> c); public <T extends E> boolean addAll(Collection<T> c); }

Questo:
Quando usar mtodos genricos? Quando usar curingas?

S use mtodos genricos quando no for possvel usar curingas


Se no existir dependncia entre parmetros e/ou tipos de retorno, deve-se preferir curingas
17

Genricos esto para ficar


Genricos esto em toda a API Java
Aprenda a us-los. No tente fugir deles! Familiarize-se com a sintaxe (vai ficar mais simples com o tempo e o costume) e evite abusar dela: quando algo puder ser feito de duas formas prefira sempre a mais simples

Duas implementaes equivalentes


Qual voc escolheria?
a) b)
public static <T> void copy(List<T> dest, List<? extends T> src) {} public static <T, S extends T> void copy(List<T> dest, List<S> src) {}

Familiarize-se com a sintaxe. Use generics j!


99% das aplicaes resolvem tudo com sintaxe simples Qual o tipo de history?
static List<List<? extends Shape>> history = new ArrayList<List<? extends Shape>>();

18

Cdigo legado em genricos


Como usar APIs e frameworks em cdigo antigo, no seu cdigo novo que usa genricos?
No preciso fazer nada de especial. Basta tratar o cdigo como se fosse pr-Java 5.0

Exemplo: pode-se passar para um mtodo que aceita Classe, qualquer Classe<Tipo>
Classe um tipo cru (raw type). parecido com Classe<?> mas no causa nenhuma verificao de preciso de tipos inseguro, portanto o compilador imprime um aviso (warning) que no pode garantir a preciso do cdigo Tipos crus existem apenas para garantir a compatibilidade reversa

19

Genricos em cdigo legado


Como usar APIs novas (com genricos) em cdigo antigo?
Isto j acontece se voc compila seu cdigo antigo que usa collections no Java 5.0 Voc pode passar tipos crus para tipos genricos checados sem causar erro de compilo O compilador no tem como garantir a preciso dos tipos e avisa com um warning.

Se todo o seu cdigo usar genricos, toda a verificao de tipos de referncia ser feita em tempo de compilao e no haver erro de cast
20

Equivalncia
O que voc acha que o trecho seguinte imprime?
List <String> strings = new ArrayList<String>(); List <Integer> integers = new ArrayList<Integer>(); System.out.println(strings.getClass().getName()); System.out.println(integers.getClass().getName()); System.out.println(strings.getClass() == integers.getClass());

java.util.ArrayList java.util.ArrayList true

O motivo
Todas as instncias de uma classe genrica tem a mesma classe em tempo de execuo, indepentemente dos parmetros de tipo passados

Uma classe no mais sinnimo de tipo


Uma classe genrica pode ter muitos tipos
21

Casts e instanceof
Como classes de tipos diferentes so equivalentes, no faz sentido usar cast ou instanceof com tipos genricos O seguinte trecho ilegal (causa erro de compilao)
Collection cs = new ArrayList<String>(); if (cs instanceof Collection<String>) { ... }

O trecho abaixo causa aviso (warnings do compilador) j que a informao de cast no til para o sistema de tempo de execuo
Collection <String> cstr = (Collection<String>) cs;

Casts com variveis de tipo so inteis, uma vez que elas no existem em tempo de execuo (causa warning)
<T> T badCast(T t, Object o) { return (T)o; }
22

Arrays
O tipo dos componentes de um array de tipos genricos no pode ser uma varivel de tipo O seguinte trecho ilegal
List<String>[] lsa = new List<String>[10]; // ERRO!!

O seguinte trecho permitido, porm causa um aviso do compilador (pode causar erro de tempo de execuo)
List<String>[] lsa = new List<?>[10]; // advertncia! String s = lsa[0].get(0); // possvel erro runtime

O seguinte trecho legal, porm para extrair um String do array ser preciso usar cast
List<?>[] lsa = new List<?>[10]; // ok! String s = (String) lsa[0].get(0);
23

java.lang.Class
No Java 1.5, java.lang.Class genrico! Pode-se fazer
Class<String> c = String.class; Class<Pessoa> pc = Class.forName(Pessoa); Employee e = new Employee(); Class<Employee> = e.getClass();

O mtodo newInstance() agora retorna um objeto do tipo da classe onde chamado


Pessoa joao = pc.newInstance();
24

Como comear a usar genricos


Explore a documentao
Veja principalmente o pacote de colees de Java: reveja as classes que voc j usa e as novas assinaturas dos mtodos

Aplique genricos no seu cdigo


Crie novos programas usando genricos Altere programas existentes gradualmente Compile (javac) usando a opo Xlint para identificar trechos obsoletos
No Ant, use <javac ...> <compilerarg line=-Xlint ...>
25

Fontes de pesquisa
[1] Gilad Bracha, Generics in the Java Programming Language a.k.a The Generics Tutorial, Julho de 2004.
Distribudo com a documentao Java. A maior parte desta apresentao foi construdo com exemplos desse tutorial.

[2] James Gosling, Bill Joy, Guy Steele e Gilad Bracha, The Java Language Specification, 3rd Edition. Addison-Wesley, 2005 (disponvel em java.sun.com).
Tpicos de interesse: 4.4 Type Variables, 4.5 Parameterized Types, 4.6 Type Erasure, 4.7 Reifiable Types, 4.8 Raw Types, 4.9 Intersection Types, 8.1.2 Generic Classes and Type Parameters, 8.4.4 Generic Methods, 8.8.4 Generic Constructors, 9.1.2 Generic Interfaces (e vrios outros) www.langer.camelot.de/GenericsFAQ/JavaGenericsFAQ.html Contm uma investigao detalhada sobre os aspectos mais obscuros de Java Generics mindview.net/WebLog/log-0061 Discusso explorando as diferenas entre C++ Templates e Java Generics, procurando solues para os principais problemas

[3] Angelika Langer, The Generics FAQ. 2004-2005


[4] Bruce Eckel, Templates vs. Generics, 08/2004

2004-2005, Helder da Rocha www.argonavis.com.br

26

Você também pode gostar