Um tipo genérico é uma classe ou interface genérica que é parametrizada em tipos. A seguinte classe Box será modificada para demonstrar o conceito.
Uma classe Box simples
Comece examinando uma classe Box não genérica que opera em objetos de qualquer tipo. Ele precisa apenas fornecer dois métodos: set, que adiciona um objeto à caixa, e get, que o recupera:
Visto que seus métodos aceitam ou retornam um objeto, você está livre para passar o que quiser , desde que não seja um dos tipos primitivos. Não há como verificar, em tempo de compilação, como a classe é usada. Uma parte do código pode colocar um número inteiro na caixa e esperar obter números inteiros dele, enquanto outra parte do código pode passar por engano em uma string, resultando em um erro de tempo de execução.
Uma versão genérica da classe Box
Uma classe genérica é definida com o seguinte formato:
class name<T1, T2, ..., Tn> { /* ... */ }
Para atualizar o Classe Box para usar genéricos, você cria uma declaração de tipo genérico alterando o código “public class Box” para “public class Box < T > “. Isso introduz a variável de tipo, T, que pode ser usada em qualquer lugar dentro da classe.
Com essa mudança, a classe Box torna-se:
Como você pode ver, todas as ocorrências de Objeto são substituída por T. Uma variável de tipo pode ser qualquer tipo não primitivo que você especificar: qualquer tipo de classe, qualquer tipo de interface, qualquer tipo de array ou até mesmo outra variável de tipo.
Essa mesma técnica pode ser aplicada para criar interfaces genéricas.
Convenções de nomenclatura de parâmetro de tipo
Por convenção, os nomes de parâmetro de tipo são letras maiúsculas simples. Isso contrasta fortemente com as convenções de nomenclatura de variáveis que você já conhece, e por um bom motivo: Sem essa convenção, seria difícil dizer a diferença entre uma variável de tipo e uma classe comum ou nome de interface.
Os nomes de parâmetro de tipo mais comumente usados são:
- E – Elemento (usado extensivamente pelo Java Collections Framework)
- K – Chave
- N – Número
- T – Tipo
- V – Valor
- S, U, V etc. – 2º, 3º, 4º tipos
Você verá esses nomes usados em toda a API Java SE e no restante desta lição.
Invocando e instanciando um tipo genérico
Para fazer referência à classe Box genérica de dentro do seu código, você deve executar uma invocação de tipo genérico, que substitui T por algum valor concreto, como Integer:
Box<Integer> integerBox;
Você pode pensar em uma invocação de tipo genérico como sendo semelhante a uma invocação de método comum, mas em vez de passar um argumento para am ethod, você está passando um argumento de tipo – inteiro neste caso – para a própria classe Box.
Como qualquer outra declaração de variável, este código não cria um novo objeto Box. Ele simplesmente declara que integerBox conterá uma referência a uma “Caixa de Inteiro”, que é como Box < Integer > é lido.
Uma invocação de um tipo genérico é geralmente conhecida como um tipo parametrizado.
Para instanciar essa classe, use a nova palavra-chave, como de costume, mas coloque < Número inteiro > entre o nome da classe e o parêntese:
Box<Integer> integerBox = new Box<Integer>();
The Diamond
No Java SE 7 e posterior, você pode substituir os argumentos de tipo necessários para invocar o construtor de uma classe genérica por um conjunto vazio de argumentos de tipo (< >) desde que o compilador possa determinar, ou inferir, os argumentos de tipo do contexto. Este par de colchetes angulares, < >, é informalmente chamado de diamante. Por exemplo, você pode criar uma instância de Box < Integer > com a seguinte instrução:
Box<Integer> integerBox = new Box<>();
Para obter mais informações sobre notação de diamante e inferência de tipo, consulte Inferência de tipo.
Parâmetros de tipo múltiplo
Conforme mencionado anteriormente, uma classe genérica pode ter vários parâmetros de tipo.Por exemplo, a classe OrderedPair genérica, que implementa a interface Pair genérica:
As instruções a seguir criam duas instanciações da classe OrderedPair:
O código, new OrderedPair < String, Integer >, instancia K como String e V como Integer. Portanto, os tipos de parâmetro do construtor OrderedPair são String e Integer, respectivamente. Devido ao autoboxing, é válido passar uma String e um int para a classe.
Conforme mencionado em The Diamond, porque um O compilador Java pode inferir os tipos K e V a partir da declaração OrderedPair < String, Integer >, essas declarações podem ser encurtadas usando a notação de diamante:
OrderedPair<String, Integer> p1 = new OrderedPair<>("Even", 8);OrderedPair<String, String> p2 = new OrderedPair<>("hello", "world");
Para criar uma interface genérica, siga as mesmas convenções para criar uma classe genérica.
Tipos parametrizados
OrderedPair<String, Box<Integer>> p = new OrderedPair<>("primes", new Box<Integer>(...));