Paradigmas da Programação PPROG GENÉRICOS (Livro Big Java, Late Objects – Capítulo 18) Nelson Freire (ISEP–DEI-PPROG 2014/15) 1/23 Genéricos Sumário Noção de Genérico Interesse dos Genéricos Tipos Parametrizados Implementação Classe Genérica Método Genérico Genéricos e Herança Tipos Wildcard Type Erasure Contexto Estático Bibliografia Nelson Freire (ISEP–DEI-PPROG 2014/15) 2/23 Noção de Genérico Genéricos 1/2 Genéricos Facilidade do Java Java 5 (2004) Atual Java 8 (2014) Permite construção Tipos Classes Interfaces Para funcionarem com objetos de vários tipos. Métodos Construções designadas Genéricas Exemplos Tipos genéricos Classes genéricas Interfaces genéricas Métodos genéricos Nelson Freire (ISEP–DEI-PPROG 2014/15) 3/23 Noção de Genérico Genéricos 2/2 Tipos e Métodos Genéricos Têm um/mais parâmetros de tipo genérico // genérico = não concreto ; Ex: tipo E Funcionam como variáveis // análogo aos parâmetros de métodos Passagem de tipos … concretos // Ex: tipo String Exemplos Exemplo Classe Genérica Declaração ... com tipo(s) genérico(s) public class ArrayList<E> ... // E: parâmetro de tipo genérico Uso ... com vários tipos referência concretos (Instâncias de tipo genérico) ArrayList<Figura> f ArrayList<Pessoa> p // <...> parêntesis angulares // Variável Interface Genérica public interface Map<K,V> Método Genérico public static void shuffle(List<?> list) // K e V: parâmetros de tipo genérico // Classe Collections Map<Integer,String> Map<Departamento, List<Empregado> > Collections.shuffle(f) Collections.shuffle(p) // ?: parâmetro de tipo genérico = qualquer tipo Nelson Freire (ISEP–DEI-PPROG 2014/15) 4/23 Interesse dos Genéricos Genéricos 1/2 Programação mais segura Mais robusta Figura area() Reduzir possibilidade de erros de execução Devido a excessivos downcastings Retangulo area() Problema Exemplo Circulo area() // Contentor que permite guardar objetos de qualquer tipo List figuras = new ArrayList(); // Elementos tipo Object // Preenchimento do contentor figuras.add( new Circulo() ); figuras.add( new Rectangulo() ); figuras.add( new Pessoa() ); // Adicionado objeto não Figura // Compilador aceita qualquer objeto // Varrimento do contentor para mostrar áreas for( Object obj : figuras ) System.out.println(((Figura) obj).area() ); Downcasting do objeto Pessoa provoca erro de execução programação insegura Nelson Freire (ISEP–DEI-PPROG 2014/15) 5/23 Interesse dos Genéricos Genéricos 2/2 Programação mais segura Solução Exemplo Usando tipo genérico ArrayList<E> // Contentor para guardar apenas objetos tipo Figura List<Figura> figuras = new ArrayList(); // Elementos tipo Figura // Preenchimento do contentor figuras.add( new Circulo() ); figuras.add( new Rectangulo() ); figuras.add( new Pessoa() ); // ERRO de COMPILAÇÃO // Compilador só aceita objetos Figura // Varrimento do contentor para mostrar áreas for( Figura figura : figuras ) System.out.println( figura.area() ); Não há downcasting programação segura Figura area() Retangulo area() Nelson Freire (ISEP–DEI-PPROG 2014/15) Circulo area() 6/23 Tipo Parametrizado Genéricos 1/2 Definição Tipo obtido por instanciação do tipo genérico, substituindo os parâmetros de tipo genérico (ex: E) por tipos referência concretos (ex: String) Exemplo Interface List genérica Tipo Genérico ( Ex: List<E> ) instanciado Tipo Parametrizado ( Ex: List<String> ) substituído (Parâmetro Tipo Genérico) public interface List<E> … { (Parâmetro Tipo Concreto) public interface List<String> … { … … boolean add(E e); boolean add(String e) } } Instanciação de Tipo Genérico Tipos Concretos Só tipos referência // tipos primitivos são ilegais Nelson Freire (ISEP–DEI-PPROG 2014/15) 7/23 Tipo Parametrizado Genéricos 2/2 Pode ser usado Declarações Variáveis … locais/atributos Parâmetros … de métodos/construtores Tipos de retorno … de métodos public class DemoUsoTipoParametrizado { … private List<String> variavel; … public DemoUsoTipoParametrizado(List<String> lista){ … } … public void metodo1(List<Pessoa> lista){ … } … public List<String> metodo2(){ … List<String> lista = new ArrayList(); … } } Uso de Tipo Parametrizado Nelson Freire (ISEP–DEI-PPROG 2014/15) 8/23 Implementação de Classe Genérica Genéricos Parâmetros de Tipo Genérico (1/2) Declaração A seguir ao nome da classe Entre parêntesis angulares // < ... > 1/2 public class ArrayList<E> … { … public boolean add(E e){…} } Declaração de ArrayList Genérico Especifica variáveis ... de instância Uma por parâmetro de tipo genérico Separadas por vírgulas Nome de variáveis Pode ser qualquer Por convenção Letra maiúscula Nome de Variável Tipo Genérico public class HashMap<K,V> … { … public V put(K key, V value){…} } Declaração de HashMap Genérico Significado E Tipo de elemento de uma coleção K Tipo key num mapa V Tipo value num mapa T Tipo genérico S, U Tipos genéricos adicionais Convenção Java Nelson Freire (ISEP–DEI-PPROG 2014/15) 9/23 Implementação de Classe Genérica Genéricos 2/2 Parâmetros de Tipo Genérico (2/2) Usados Parâmetro de tipo genérico no cabeçalho da classe Só contexto de instância Ilegal em contexto estático Atributos de instância Variáveis estáticas Construtores Métodos estáticos Classe internas estáticas Tipos de Parâmetros Corpo Métodos de instância Tipo de Parâmetro Tipo de Retorno Corpo public class DemoClasseGenerica<T> { … private T variavel; … public DemoClasseGenerica(T obj){…} … public void metodo1(T obj){…} Classes internas public T metodo2(){…} public T metodo3(T obj) {…} Não-estáticas … private class classeInterna<T> … {…} } Exemplos de Uso de Parâmetro de Tipo Genérico Nelson Freire (ISEP–DEI-PPROG 2014/15) 10/23 Implementação de Método Genérico Genéricos 1/2 Método Genérico Método com um/mais parâmetros de tipo genérico Implementação de Método Genérico Tipo de Classe Tipo de Método Instância Classe Genérica Classe Não-Genérica (sem parâmetros de tipo genérico) Nelson Freire (ISEP–DEI-PPROG 2014/15) Parâmetros de Tipo Utilizáveis Próprios Cabeçalho da classe Classe (estático) Próprios Instância Próprios Classe (estático) Próprios 11/23 Implementação de Método Genérico Genéricos 2/2 Método Genérico de Classe Não-Genérica Especifica tipo genérico próprio Declaração Antes do tipo de retorno Exemplo Método de classe public class Servicos { … public static <T> void … } } imprimir( T[] vetor ) { Método que imprime qualquer tipo de vetor Invocação Chamada convencional Exemplo Servicos.imprimir( nomes ); // String[] nomes Não é preciso … indicar o tipo concreto do parâmetro de tipo genérico Compilador deduz o tipo referência concreto // tipos primitivos ilegais Nelson Freire (ISEP–DEI-PPROG 2014/15) 12/23 Genéricos e Herança Genéricos 1/2 Herança em Parâmetros de Tipo Concreto Não implica herança de classes parametrizadas Figura area() Exemplo ArrayList<Figura> e ArrayList<Retangulo> Não existe relação de herança entre arraylists Retangulo area() Circulo area() Retangulo é subtipo de Figura Parâmetros de tipo estão relacionados por herança Não é possível: ArrayList<Retangulo> listaRetangulos = new ArrayList(); ArrayList<Figuras> listaFiguras = listaRetangulos; // Ilegal Justificação Caso contrário Possível adicionar objetos de tipos não relacionados por herança a contentor Exemplo ArrayList<Figura> figuras = new ArrayList<>(); ArrayList<Retangulo> retangulos = new ArrayList<>(); ... figuras = retangulos; // Se fosse legal ... figuras.add( new Circulo() ); // ... era possível adicionar um circulo ... aos retangulos Nelson Freire (ISEP–DEI-PPROG 2014/15) 13/23 Genéricos e Herança Genéricos 2/2 Implicações da Limitação Exemplo public class MinhaLista<E> { … public MinhaLista(List<E> lista){…} … } Tipo Parametrizado MinhaLista<Figura> Figura area() Parâmetro List<E> Permite Passagem Listas de tipo E Retangulo area() Circulo area() Exemplo new MinhaLista( new ArrayList<Figura>() ) Não Permite Passagem Listas de subtipos/supertipos de E Exemplo new MinhaLista( new ArrayList<Circulo>() ) Ultrapassar Limitação Tipos Wildcard Nelson Freire (ISEP–DEI-PPROG 2014/15) 14/23 Tipos Wildcard Genéricos 1/5 Interesse Restringir os tipos concretos passados através de parâmetros genéricos Tipos Wildcard Nome Sintaxe Significado Obs Wildcard com restrição inferior ? extends B Qualquer tipo/subtipo de B (limitado ao tipo e subtipos de B) ? = qualquer tipo extends = tipo/subtipo B = classe/interface Wildcard com restrição superior ? super B Qualquer tipo/supertipo de B super = tipo/supertipo Wildcard sem restrições ? Qualquer tipo Tipo Wildcard Tipo desconhecido // não é preciso conhecer tipo específico Exemplo public class ArrayList<E> … { … public ArrayList(Collection<? extends E> c) { … } } Construtor Cria arraylist com elementos de c Não precisa de saber ... tipo específico dos elementos de c Permite elementos de c do tipo/subtipo de E Nelson Freire (ISEP–DEI-PPROG 2014/15) 15/23 Tipos Wildcard Genéricos 2/5 Wildcard com Restrição Inferior Restrição inferior do tipo limitado ao tipo e subtipos Nome Sintaxe Wildcard com restrição inferior ? extends B Significado Qualquer tipo/subtipo de B Obs ? = qualquer tipo extends = subtipo B = classe/interface Exemplo public class ArrayList<E> … { … public ArrayList(Collection<? extends E> c) { … } } Construtor Não precisa de saber tipo específico de elementos de c Permite elementos de c do tipo/subtipo de E Figura Retangulo Circulo Exemplo - ArrayList<Figura> List<Figura> listaFiguras = new ArrayList(listaCirculos); List<Circulo> listaCirculos = new ArrayList(); ... List<Figura> listaFiguras = new ArrayList(listaRetangulos); List<Retangulo> listaRetangulos = new ArrayList(); Nelson Freire (ISEP–DEI-PPROG 2014/15) 16/23 Tipos Wildcard Genéricos 3/5 Wildcard com Restrição Superior Restrição superior do tipo limitado ao tipo e supertipos Nome Sintaxe Wildcard com restrição superior ? super B Significado Qualquer tipo/supertipo de B Obs ? = qualquer tipo super = supertipo B = classe/interface Exemplo public class ArrayList<E> … { … public void sort(Comparator<? super E> c){ … } } Método sort Não precisa de saber tipo específico de objetos comparáveis Permite objeto Comparator de tipo/supertipo de E Exemplo Figura ArrayList<Circulo> Comparator<Circulo> Retangulo Circulo Comparator<Figura> Figura = supertipo de Circulo Compara objetos tipo Figura Compara objetos tipo Circulo Nelson Freire (ISEP–DEI-PPROG 2014/15) 17/23 Tipos Wildcard Genéricos 4/5 Wildcard sem Restrição Nome Sintaxe Significado Wildcard sem restrições ? Qualquer tipo Exemplo public class ArrayList<E> … { … public boolean removeAll(Collection<?> c) } Método removeAll Remove todos elementos armazenados em c Não precisa de saber tipo específico dos elementos de c Permite elementos de c de qualquer tipo Nota Collection<Object> Não equivalente a Collection<?> Só permite coleção com elementos tipo Object Nelson Freire (ISEP–DEI-PPROG 2014/15) 18/23 Tipos Wildcard Genéricos 5/5 Tipos de Declarações de Restrições: Um Tipo Múltiplos Tipos Declarações de Um Tipo Exemplos <?> <? extends E> <? super T> Declarações de Múltiplos Tipos Tipos ligados Carater & Exemplo <? extends Comparable<E> & Measurable> Nelson Freire (ISEP–DEI-PPROG 2014/15) // tipos de interfaces 19/23 JVM Substitui Parâmetros de Tipo (Type Erasure) Genéricos 1/2 Máquina Virtual do Java (JVM) Não trabalha com Tipos genéricos Métodos genéricos Razão Genéricos mais recentes que a JVM Substitui parâmetros de tipo Por tipos não parametrizados Pelo tipo Object // se não houver restrições Da restrição Exemplos ArrayList<E> E substituído por Object ArrayList ... com elementos de tipo Object // resulta numa classe normal <E extends Measurable> E substituído por Measurable Problema Introduz limitações nos genéricos Nelson Freire (ISEP–DEI-PPROG 2014/15) 20/23 Genéricos JVM Substitui Parâmetros de Tipo (Type Erasure) 2/2 Limitações Impossível construir objetos de tipo genérico Exemplos new E() // Se E substituído por Objet new Object() – nem sempre desejável // Alternativa: ArrayList<E> new E[20] // Array de tipo genérico Construção de array de tipo genérico Limitação pode ser ultrapassada Usando técnica Reflection JVM Guarda objeto Class Por cada classe carregada Objeto Class tem Informação sobre uma classe Métodos para construir novos objetos dessa classe Dado um array a de tipo genérico Class objCA = a.getClass(); // obter objeto Class do array Class objCE = objCA.getComponentType(); // obter objeto Class elementos Object[] novoArray = Array.newInstance(objCE, tamanho); Nelson Freire (ISEP–DEI-PPROG 2014/15) // criar array 21/23 Contexto Estático Genéricos Parâmetros de Tipo Genérico de uma Classe São variáveis de instância Não podem ser usados em contexto estático Variáveis estáticas Métodos estáticos // alternativa: adicionar parâmetros de tipo genérico Classes internas estáticas // alternativa: adicionar parâmetros de tipo genérico Nelson Freire (ISEP–DEI-PPROG 2014/15) 22/23 Genéricos Bibliografia Livro Big Java, Late Objects Cay S. Horstmann 2013 John Wiley & Sons Tutorial http://docs.oracle.com/javase/tutorial/java/generics/ Nelson Freire (ISEP–DEI-PPROG 2014/15) 23/23