![]() |
Introdução aos Generics |
|
![]() |
Por Francisco Demontiê dos Santos Junior(demontie@dsc.ufcg.edu.br) |
A Programação Genérica é um paradigma a partir do qual os algoritmos são escritos de forma independente do tipo de dados. Isso se dá por meio de uma gramática estendida que adiciona alguma construção que irá se adaptar a partir de definições da instância do algoritmo. Os Generics surgiram para incorporar esse paradigma à linguagem de programação Java. |
|
![]() |
e Leonardo Alves dos Santos(santos.leonardoalves@gmail.com) |
O conceito de Generics surgiu na década de 1970 com as linguagens Ada e Clu. Depois disso, outras linguagens implementaram esse conceito, porém, ele se difundiu com o surgimento dos templates C++. Em Java, esse conceito foi implementado na versão 1.5, versão que proporcionou grandes mudanças na linguagem. Mas, o que são exatamente os generics? Generics são estruturas que permitem a escrita de um algoritmo sem a preocupação com os tipos de dados. O uso dos Generics Java é bastante simples (em sua sintaxe). Para criar uma classe que possui objetos de um tipo genérico, basta acrescentar à declaração dessa uma ou mais variáveis de tipo (separadas por vírgulas). Essas variáveis são identificadores que serão substituídos por tipos escolhidos pelo programador. Elas fornecem informações em tempo de compilação e de execução. Na Listagem 1 é apresentado um exemplo simples de uso dos Generics. public class HelloWorldGenerics<T> { T obj; public void setObj(T obj){ this.obj = obj; } public String getMessage(){ return "Objeto: " + obj.toString() + "; " + obj.getClass(); } public static void main(String[] args){ HelloWorldGenerics<Integer> a = new HelloWorldGenerics<Integer>(); a.setObj(2); System.out.println(a.getMessage()); HelloWorldGenerics<String> b = new HelloWorldGenerics<String>(); b.setObj("2"); System.out.println(b.getMessage()); } } Perceba que, caso o método setObj seja chamado com um parâmetro de um outro tipo que não seja Integer, o compilador acusará um erro. É dessa forma que foram implementadas as coleções de Java. No caso da interface Map, utiliza-se duas variáveis de tipo, uma é o tipo da chave e a outra o tipo dos valores contidos no mapa. Em alguns casos, podemos precisar restringir os tipos de objetos com os quais trabalharemos. Para tal, podemos utilizar o conceito de sub tipos nos generics. Utilizamos, então, a palavra reservada extends (aqui, extends, não é referente apenas à subtipagem a partir da herança, mas também por meio de interfaces). Suponha, então, que queremos construir um algoritmo de ordenação genérico (utilizaremos, para este exemplo, o "insertion sort") e, por isso, temos que trabalhar apenas com objetos que sejam comparáveis. Veja a Listagem 2. import java.util.Arrays; public class UtilizandoGenerics { public static <T extends Comparable<T>> void selectionSort(T[] v) { int index_min; T aux; for (int i = 0; i < v.length; i++) { index_min = i; for (int j = i + 1; j < v.length; j++) { if (v[j].compareTo(v[index_min]) < 0) { index_min = j; } } if (index_min != i) { aux = v[index_min]; v[index_min] = v[i]; v[i] = aux; } } } public static void main(String[] args) { Integer[] vetor = new Integer[]{2,4,6,1,3,9,5}; selectionSort(vetor); System.out.println(Arrays.toString(vetor)); String[] vetor2 = new String[]{"b","d","f","a","c","i","e"}; selectionSort(vetor2); System.out.println(Arrays.toString(vetor2)); } } Nesse exemplo, duas coisas merecem um comentário. A primeira delas é que nossa variável de tipo T será substituída, obrigatoriamente, por alguma classe que implemente a interface Comparable. Isso nos garante que poderemos sempre comparar os elementos do array. A segunda coisa que merece destaque é o fato de a variável de tipo ter sido definida na assinatura do método, e não na assinatura da classe. Chamamos isso de "Generic Methods". Podemos nos perguntar, então, qual a vantagem de se usar esse tipo de método se poderíamos, apenas, definir o tipo de parâmetro do método por Comparable[ ] (array de Comparable). Nesse caso, funcionaria normalmente, porém, observe a Listagem 3. public static <T extends Comparable<T>> T min(List<T> l){ T min = l.get(0); for (int i=1; i < l.size(); i++) if (l.get(i).compareTo(min) < 0) min = l.get(i); return min; } public static Comparable max(List<Comparable> l){ Comparable max = l.get(0); for (int i=1; i < l.size(); i++) if (l.get(i).compareTo(max) > 0) max = l.get(i); return max; } public static void main(String[] args) { List<Integer> l = new ArrayList<Integer>(); l.add(2); l.add(7); l.add(-1); l.add(3); System.out.println("O menor elemento da lista eh: " + min(l)); System.out.println("O maior elemento da lista eh: " + max(l)); } Nesse caso, a função min invocada com parâmetro do tipo List Algumas observações:
A Programação Genérica pode ser bastante poderosa e útil, e os Generics Java são uma forma bastante simples de se programar sob os conceitos de tal paradigma. Porém, é preciso ter cuidado com certas operações e saber escolher bem a família de tipos sob as quais seus algoritmos devem atuar. Fontes: [1] http://pt.wikipedia.org/wiki/Programa%C3%A7%C3%A3o_gen%C3%A9rica. Último acesso em 22/06/2011. [2] http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf. Último acesso em 22/06/2011. |