Tutorial de exemplo de Java Generics – Método genérico, classe, interface
Java Genrics é um dos recursos mais importantes introduzidos no Java 5.
Se você tem trabalhado em coleções Java e com a versão 5 ou superior, tenho certeza de que o usou.
Genéricos em Java com classes de coleção são muito fáceis, mas fornecem muito mais recursos do que apenas criar o tipo de coleção.
Tentaremos aprender os recursos dos genéricos neste artigo. Entender os genéricos pode se tornar confuso se usarmos jargões, então eu tentaria mantê-los simples e fáceis de entender.
Genéricos em Java
Os genéricos foram adicionados ao Java 5 para fornecer verificação de tipo em tempo de compilação e remover o risco de ClassCastException
que era comum durante o trabalho com classes de coleção. Toda a estrutura da coleção foi reescrita para usar genéricos para segurança de tipos. Vamos ver como os genéricos nos ajudam a usar classes de coleção com segurança.
O código acima compila bem, mas lança ClassCastException em tempo de execução porque estamos tentando lançar Object na lista para String, enquanto um dos elementos é do tipo Integer. Depois do Java 5, usamos classes de coleção como abaixo.
Observe que no momento da criação da lista, especificamos que o tipo de elementos na lista será String. Portanto, se tentarmos adicionar qualquer outro tipo de objeto na lista, o programa gerará um erro de tempo de compilação. Observe também que, no loop for, não precisamos de typecasting do elemento na lista, portanto, removendo ClassCastException em tempo de execução.
Java Generic Class
Podemos definir nossas próprias classes com tipo genérico. Um tipo genérico é uma classe ou interface que é parametrizada em tipos. Usamos colchetes angulares (< >) para especificar o parâmetro de tipo.
Para entender o benefício, digamos temos uma classe simples como:
Observe que ao usar esta classe, temos que usar a conversão de tipo e ela pode produzir ClassCastException em tempo de execução. Agora usaremos a classe genérica java para reescrever a mesma classe mostrada abaixo.
Observe o uso da classe GenericsType no método principal. Não precisamos fazer a conversão de tipo e podemos remover ClassCastException em tempo de execução. Se não fornecermos o tipo no momento da criação, o compilador produzirá um aviso de que “GenericsType é um tipo bruto.
Referências ao tipo genérico GenericsType < T > deve ser parametrizado ”. Quando não fornecemos o tipo, o tipo se torna Object
e, portanto, permite ambas as strings e objetos inteiros. Mas, devemos sempre tentar evitar isso porque teremos que usar conversão de tipo ao trabalhar com tipo bruto que pode produzir erros de tempo de execução.
@SuppressWarnings("rawtypes")
anotação para suprimir o aviso do compilador, verifique o tutorial de anotações java. Observe também que ele suporta java autoboxing.
Java Generic Interface
A interface comparável é um ótimo exemplo de Genéricos em interfaces e é escrita como:
De maneira semelhante, podemos criar interfaces genéricas em java. Também podemos têm vários parâmetros de tipo como na interface do Mapa. ganho, podemos fornecer valor parametrizado para um tipo parametrizado também, por exemplo new HashMap<String, List<String>>();
é válido.
Tipo genérico Java
Nomenclatura de tipo genérico Java convenção nos ajuda a entender o código facilmente e ter uma convenção de nomenclatura é uma das melhores práticas da linguagem de programação Java. Portanto, os genéricos também vêm com suas próprias convenções de nomenclatura. Normalmente, os nomes dos parâmetros de tipo são letras maiúsculas simples para torná-los facilmente distinguíveis das variáveis java. Os nomes de parâmetro de tipo mais comumente usados são:
- E – Elemento (usado extensivamente pelo Java Collections Framework, por exemplo ArrayList, Set etc.)
- K – Key ( Usado no mapa)
- N – Número
- T – Tipo
- V – Valor (usado no mapa)
- S, U, V etc. – 2º, 3º, 4º tipos
Método Genérico Java
Às vezes não queremos que toda a classe seja parametrizada, nesse caso, podemos criar método genérico Java. Como o construtor é um tipo especial de método, também podemos usar o tipo genérico em construtores.
Aqui está uma classe que mostra um exemplo de um método genérico Java.
Observe o método isEqual assinatura mostrando a sintaxe para usar o tipo genérico em métodos. Além disso, observe como usar esses métodos em nosso programa java. Podemos especificar o tipo ao chamar esses métodos ou podemos invocá-los como um método normal. O compilador Java é inteligente o suficiente para determinar o tipo de variável a ser usado, esse recurso é chamado de inferência de tipo.
Parâmetros de tipo vinculado genéricos Java
Suponha que queremos restringir o tipo de objetos que podem ser usados no tipo parametrizado, por exemplo, em um método que compara dois objetos e queremos certifique-se de que os objetos aceitos sejam comparáveis. Para declarar um parâmetro de tipo limitado, liste o nome do parâmetro de tipo, seguido pela palavra-chave extends, seguida por seu limite superior, semelhante ao método abaixo.
O a invocação desses métodos é semelhante ao método ilimitado, exceto que se tentarmos usar qualquer classe que não seja Comparável, isso gerará um erro de tempo de compilação.
Parâmetros de tipo limitado podem ser usados com métodos, bem como classes e interfaces.
Java Generics também oferece suporte a limites múltiplos, ou seja, < T estende A & B & C >. Nesse caso, A pode ser uma interface ou classe. Se A for classe, então B e C devem ser uma interface. Não podemos ter mais de uma classe em vários limites.
Java Genéricos e Herança
Nós sabemos que A herança Java nos permite atribuir uma variável A a outra variável B se A for uma subclasse de B. Portanto, podemos pensar que qualquer tipo genérico de A pode ser atribuído ao tipo genérico de B, mas não é o caso. Vamos ver isso com um programa simples.
Não temos permissão para atribuir a variável MyClass < String > à variável MyClass < Variável de objeto > porque não estão relacionadas, na verdade MyClass < T > pai é objeto.
Classes e subtipagem genérica de Java
Podemos subtipar uma classe ou interface genérica estendendo ou implementando-a. A relação entre os parâmetros de tipo de uma classe ou interface e os parâmetros de tipo de outra são determinados pelas cláusulas extends e implements.
A relação de subtipagem é preservada desde que não alteremos o argumento de tipo, abaixo mostra um exemplo de parâmetros de vários tipos.
Os subtipos de Lista < String > pode ser MyList < String, Object >, MyList < String, Integer > e assim por diante.
Java Generics Wildcards
Ponto de interrogação (?) É o curinga em genéricos e representa um tipo desconhecido. O curinga pode ser usado como o tipo de um parâmetro, campo ou variável local e às vezes como um tipo de retorno. Não podemos usar curingas ao invocar um método genérico ou instanciar uma classe genérica. Nas seções a seguir, aprenderemos sobre curingas de limite superior, curingas de limite inferior e captura de curinga.
9.1) Java Generics Upper Bounded Wildcard
Os curingas de limite superior são usados para relaxar o restrição sobre o tipo de variável em um método. Suponha que queremos escrever um método que retornará a soma dos números na lista, então nossa implementação será algo como isto.
Agora, o problema com a implementação acima é que ele não funcionará com Lista de inteiros ou duplos porque sabemos que Lista < Integer > e Lista < Double > não estão relacionados, isto é, quando um curinga de limite superior é útil. Usamos curinga genéricos com a palavra-chave extends e a classe ou interface de limite superior que nos permitirá passar o argumento do limite superior ou seus tipos de subclasses.
A implementação acima pode ser modificada como o programa abaixo.
É semelhante a escrever nosso código em termos de interface, no método acima podemos usar todos os métodos da classe de limite superior Número. Observe que, com a lista de limite superior, não temos permissão para adicionar nenhum objeto à lista, exceto null. Se tentarmos adicionar um elemento à lista dentro do método sum, o programa não compilará.
9.2) Java Generics Unbounded Wildcard
Às vezes temos uma situação em que deseja que nosso método genérico funcione com todos os tipos, neste caso, um curinga ilimitado pode ser usado. É o mesmo que usar <? extends Object >.
Podemos fornecer List < String > ou List < Integer > ou qualquer outro tipo de argumento da lista de objetos para o Método printData. Semelhante à lista do limite superior, não temos permissão para adicionar nada à lista.
9.3) Java Generics Lower bounded Wildcard
Suponha que queremos adicionar Inteiros a uma lista de inteiros em um método, podemos manter o tipo de argumento como List < Integer >, mas será vinculado a números inteiros, enquanto Lista < Número > e Lista < O objeto > também pode conter inteiros, portanto, podemos usar um curinga de limite inferior para fazer isso. Usamos curinga genérico (?) Com super palavra-chave e classe de limite inferior para conseguir isso.
Podemos passar o limite inferior ou qualquer supertipo de limite inferior como argumento, neste caso, o compilador java permite adicionar o limite inferior vinculou tipos de objetos à lista.
Subtipagem usando curinga genérico
Apagamento de tipo genérico Java
Genéricos em Java foi adicionado para fornecer verificação de tipo em tempo de compilação e não tem uso em tempo de execução, portanto, o compilador java usa o recurso de eliminação de tipo para remover todo o código de verificação de tipo genérico no código de byte e inserir conversão de tipo, se necessário. O apagamento de tipo garante que nenhuma nova classe seja criada para tipos parametrizados; conseqüentemente, os genéricos não geram sobrecarga de tempo de execução.
Por exemplo, se tivermos uma classe genérica como a abaixo;
O compilador Java substitui o parâmetro de tipo limitado T pela primeira interface associada, Comparable , conforme o código abaixo:
FAQs genéricos
12.1) Por que usamos genéricos em Java?
Os genéricos fornecem verificação de tipo forte em tempo de compilação e reduzem o risco de ClassCastException e conversão explícita de objetos.
12.2) O que é T em genéricos?
Usamos < T > para criar uma classe, interface e método genéricos. OT é substituído pelo tipo real quando o usamos.
12.3) Como os genéricos funcionam em Java?
O código genérico garante a segurança do tipo. O compilador usa o apagamento de tipo para remover todos os parâmetros de tipo no tempo de compilação para reduzir a sobrecarga no tempo de execução.
Genéricos em Java – leituras adicionais
Isso é tudo para genéricos em java, java genéricos é um tópico muito vasto e requer muito tempo para ser entendido e usado com eficácia. Esta postagem aqui é uma tentativa de fornecer detalhes básicos de genéricos e como podemos usá-los para estender nosso programa com segurança de tipo.