java generics tutorial with examples
Genéricos Java são um conjunto de recursos que permitem que você grave código independentemente do tipo de dados. Este artigo explica os Genéricos Java em detalhes com exemplos:
Os genéricos são um dos recursos importantes do Java e foram introduzidos a partir do Java 5.
Por definição, os Genéricos são um conjunto de recursos da linguagem Java que permitem ao programador usar tipos e funções genéricos e, assim, garantir a segurança dos tipos.
O que você aprenderá:
Como funcionam os genéricos em Java?
Se você já trabalhou com C ++ antes, Java Generics é igual aos modelos em C ++. Java Generics permite incluir um parâmetro em sua definição de classe / método que terá o valor de um tipo de dados primitivo.
Por exemplo, você pode ter uma classe genérica “Array” da seguinte maneira:
Matriz de classe {….}
Onde está o tipo parametrizado.
Em seguida, você pode criar objetos para esta classe da seguinte maneira:
Array int_array = new Array () Array char_array = new Array ();
Assim, dada uma classe parametrizada genérica, você pode criar objetos da mesma classe com diferentes tipos de dados como parâmetros. Esta é a principal essência do uso de Java Generics.
Da mesma forma, você pode escrever um método genérico com um tipo parametrizado para classificar uma matriz e, em seguida, instanciar esse método para qualquer tipo primitivo.
Java Generics são usados principalmente com a estrutura de coleções de Java. As diferentes coleções como LinkedList, List, Map, HashMap, etc. usam Genéricos para implementação. Os genéricos fornecem segurança de tipo, pois a verificação de tipo é feita em tempo de compilação, tornando seu código mais estável.
Vamos agora mais aos detalhes das classes e métodos genéricos, bem como outros tópicos relacionados.
Classes Genéricas
Uma classe genérica é igual a uma classe normal, exceto que o nome da classe é seguido por um tipo entre colchetes angulares.
Uma definição geral de uma classe genérica é a seguinte:
class class_name
{
variáveis de classe;
… ..
métodos de classe;
}
Depois que a classe é definida, você pode criar objetos de qualquer tipo de dados que desejar, da seguinte maneira:
class_name obj = new class_name ();
Por exemplo, para o objeto Integer, a declaração será:
class_name obj = new class_name;
Da mesma forma, para o tipo de dados String, o objeto será:
class_name str_Obj = new class_name;
Um exemplo de implementação para a classe Genérica é mostrado abaixo.
class MyGenericClass { T obj; void add(T obj) { this.obj=obj; } T get() { return obj; } } class Main { public static void main(String args()) { MyGenericClass m_int=new MyGenericClass(); m_int.add(2); MyGenericClassmstr=new MyGenericClass(); mstr.add('SoftwaretestingHelp'); System.out.println('Member of MyGenericClass:' + m_int.get()); System.out.println('Member of MyGenericClass:' + mstr.get()); } }
Resultado:
No programa acima, uma classe MyGenericClass é uma classe genérica. Ele tem dois métodos, ou seja, adicionar e obter. O método add inicializa o objeto genérico enquanto os métodos get retornam o objeto.
Na função principal, declaramos dois objetos do tipo Integer e String cada. Inicializamos esses dois objetos com seus respectivos valores iniciais usando o método add e, em seguida, geramos o conteúdo desses objetos usando o método get.
Apresentamos o exemplo da classe Genérica acima com um parâmetro de tipo. Mas, na realidade, uma classe também pode ter mais de um parâmetro de tipo. Nesse caso, os parâmetros de tipo são separados por uma vírgula.
O exemplo a seguir demonstra isso:
classTest_Generics { T1 obj1; // An object of type T1 T2 obj2; // An object of type T2 // constructor to initialise T1 & T2 objects Test_Generics(T1 obj1, T2 obj2) { this.obj1 = obj1; this.obj2 = obj2; } public void print() { System.out.println('T1 Object:' + obj1); System.out.println('T2 Object:' + obj2); } } class Main { public static void main (String() args) { Test_Genericsobj = newTest_Generics('Java Generics', 1); obj.print(); } }
Resultado:
Neste programa, temos dois parâmetros de tipo, ou seja, T1 e T2. Temos funções para inicializar os objetos membros e também para imprimir o conteúdo. Na função principal, declaramos um objeto com dois tipos, ou seja, String e Integer. A saída do programa mostra o conteúdo do objeto criado.
Assim como as classes, você também pode ter interfaces genéricas. Aprenderemos tudo sobre interfaces em um tópico separado.
Métodos Genéricos Java
Assim como você pode ter classes e interfaces genéricas, também pode ter métodos genéricos, caso não precise que uma classe inteira seja genérica.
O programa a seguir mostra a implementação do método genérico “printGenericArray”. Observe a chamada do método na função principal. Aqui, fazemos duas chamadas ao método Genérico, primeiro com type e depois com type.
public class Main{ public static void printGenericArray(T() items) { for ( T item : items){ System.out.print(item + ' '); } System.out.println(); } public static void main( String args() ) { Integer() int_Array = { 1, 3, 5, 7, 9, 11 }; Character() char_Array = { 'J', 'A', 'V', 'A', 'T','U','T','O','R','I','A', 'L','S' }; System.out.println( 'Integer Array contents:' ); printGenericArray(int_Array ); System.out.println( 'Character Array contents:' ); printGenericArray(char_Array ); } }
Resultado:
Parâmetros de tipo limitado
Parâmetros de tipo delimitado entram em cena quando você deseja limitar os tipos de dados em genéricos. Por exemplo, se você deseja uma classe ou método genérico específico ou qualquer interface que deva funcionar apenas para tipos de dados numéricos, você pode especificar isso usando a palavra-chave “extends”.
Isso é mostrado abaixo:
List myList = new ArrayList(); List list1 = new ArrayList();
As duas declarações acima serão aceitas pelo compilador, pois Long e Integer são subclasses de Number.
A próxima declaração, entretanto, será um problema.
List list = new ArrayList();
Isso gerará um erro em tempo de compilação porque String não é um número. O símbolo '?' No exemplo acima é conhecido como curinga e iremos discuti-lo a seguir.
diferença entre teste de unidade e integração
Portanto, em geral, os parâmetros de tipo limitado são usados principalmente quando você deseja restringir os tipos de dados a serem usados em seu código genérico.
Java Generics Wildcard
Em Java, um curinga é denotado por um ponto de interrogação, '?' Que é usado para se referir a um tipo desconhecido. Os curingas são usados principalmente com genéricos como tipo de parâmetro.
Ao usar curingas genéricas, você deve se lembrar de um ponto que, embora o objeto seja a superclasse de todas as outras classes, a coleção de objetos ( Por exemplo, Lista) não é uma superclasse de todas as outras coleções.
Além de ser usado como um tipo de parâmetro, você pode usar um curinga como um campo, uma variável local e como tal. No entanto, você nunca pode usar um curinga como um supertipo, ou como um argumento de tipo para invocar um método genérico ou no caso de criação de uma instância de uma classe genérica.
Existem muitos exemplos de tipos parametrizados por curinga (aqui, pelo menos um argumento de tipo é um curinga), conforme mostrado abaixo, e os curingas usados em diferentes lugares serão interpretados de forma diferente:
- Coleção <: Coleção denota todas as instanciações da interface de coleção, independentemente do argumento de tipo usado.
- Lista extends Number< : Lista representa todos os tipos de lista onde o tipo de elemento será um número.
- Comparador: Todas as instanciações da interface do comparador para argumentos de tipo que são Stringsupertypes.
Observe que um tipo Parametrizado curinga é uma regra imposta para reconhecer tipos válidos. Não é um tipo de dado concreto. Os curingas genéricos podem ser limitados ou ilimitados.
# 1) Caracteres curinga ilimitados
Em Unbounded Wildcards, não há restrições nas variáveis de tipo e é denotado da seguinte forma:
ArrayList mylist = new ArrayList(); ArrayList my_strList = new ArrayList();
# 2) Caracteres curinga limitados
Já discutimos os tipos limitados. Isso impõe restrições ao tipo de dados usado para instanciar os parâmetros de tipo usando as palavras-chave - extends ou super. Esses curingas podem ser divididos em curingas de limite superior e curingas de limite inferior.
- Caracteres curinga de limite superior
Se quiser que sua expressão genérica seja válida para todas as subclasses de um determinado tipo, especifique o curinga de limite superior com a palavra-chave extends.
quem é o melhor provedor de e-mail
Por exemplo, suponha que você precise de um método genérico que suporte List, List, etc., então você pode especificar um Upper Bounded Wildcard como Lista . Como Number é uma superclasse, este método genérico funcionará para todas as suas subclasses.
O programa a seguir demonstra isso.
importjava.util.*; public class Main { private static Number summation (List numbers){ double sum = 0.0; for (Number n : numbers) sum += n.doubleValue(); return sum; } public static void main(String() args) { //Number subtype : Integer Listint_list = Arrays.asList(1,3,5,7,9); System.out.println('Sum of the elements in int_list:' + summation(int_list)); //Number subtype : Double List doubles_list = Arrays.asList(1.0,1.5,2.0,2.5,3.0,3.5); System.out.println('Sum of the elements in doubles_list:' + summation(doubles_list)); } }
Resultado:
Aqui, fornecemos um caractere curinga de limite superior, List para o argumento de tipo da função “soma”. Na função principal, definimos duas listas, ou seja, int_list do tipo Integer e doubles_list do tipo Double. Como Integer e Double são as subclasses de Number, o somatório da função funciona perfeitamente em ambas as listas.
- Caracteres curinga de limite inferior
Se quiser que a expressão genérica aceite todas as superclasses de um tipo específico, você pode especificar um Curinga Limite Inferior para o seu argumento de tipo.
Um exemplo de implementação para isso é fornecido abaixo:
importjava.util.*; class Main { public static void main(String() args) { //Integer List ListInt_list= Arrays.asList(1,3,5,7); System.out.print('Integer List:'); printforLowerBoundedWildcards(Int_list); //Number list ListNumber_list= Arrays.asList(2,4,6,8); System.out.print('Number List:'); printforLowerBoundedWildcards(Number_list); } public static void printforLowerBoundedWildcards(List list) { System.out.println(list); } }
Resultado:
Neste programa, o Lower Bounded Wildcard especificado é “List”. Então, na função principal, temos uma lista de tipos e a lista. Como usamos o Lower Bounded Wildcard, a classe Number é uma superclasse de Integer é um argumento de tipo válido.
Vantagens de Genéricos Java
# 1) Segurança de tipo
Os genéricos garantem a segurança de tipo. Isso significa que a verificação de tipo é feita em tempo de compilação e não em tempo de execução. Portanto, não há chance de obter “ClassCastException” durante o tempo de execução, pois os tipos corretos serão usados.
importjava.util.*; class Main { public static void main(String() args) { List mylist = new ArrayList(); mylist.add(10); mylist.add('10'); System.out.println(mylist); List list = new ArrayList(); list.add(10); list.add('10');// compile-time error System.out.println(list); } }
No programa acima, temos duas listas, uma sem genéricos e outra com genéricos. Na lista não genérica, não há segurança de tipo. Você pode adicionar um inteiro, string, etc. como um elemento e ele é aceito.
Na lista genérica, você pode adicionar apenas um tipo de elemento que é especificado na expressão genérica. Se você tentar adicionar um elemento de outro tipo, isso resultará em um erro de tempo de compilação.
No programa acima, o erro de tempo de compilação é exibido na linha:
list.add('10');
# 2) Reutilização de código
Usando Genéricos, você não precisa escrever um código separado para cada tipo de dados. Você pode escrever uma única classe ou método etc. e usá-lo para todos os tipos de dados.
# 3) Não há necessidade de modelagem
Como você está usando Genéricos, o compilador conhece os tipos usados, então não há necessidade de conversão de tipos.
Considere o código abaixo:
List mylist = new ArrayList(); mylist.add('Java'); String mystr = (String) list.get(0); //typecasting required
Como você pode ver, quando uma lista normal é usada, você precisa converter o elemento da lista em seu tipo apropriado da maneira que é feito para o mystr acima.
Agora vamos escrever o mesmo código novamente com uma lista genérica.
List list = new ArrayList(); list.add('Java'); String mystr = list.get(0);
Aqui, especificamos o tipo de string como uma expressão genérica para a declaração da lista. Portanto, para recuperar elementos individuais dessa lista, não precisamos fazer um typecast.
# 4) Implementar Algoritmos Genéricos
Você pode implementar muito mais algoritmos genéricos ao usar os genéricos para codificar.
# 5) Verificação de tempo de compilação
Como já mencionado, quando você usa Genéricos em seu programa Java, o compilador verifica os tipos no momento da compilação, evitando assim o encerramento anormal do programa em tempo de execução.
perguntas frequentes
P # 1) Por que usamos Genéricos em Java?
Responda: Os genéricos garantem a independência de tipo, ou seja, podemos fornecer um parâmetro de tipo ao definir uma classe / interface / método, etc., para que durante a instanciação real possamos especificar o tipo real. Dessa forma, também fornecemos capacidade de reutilização de código.
P # 2) Os genéricos são importantes em Java?
Responda: sim. Na verdade, os genéricos são os recursos mais importantes do Java para garantir a segurança de tipo, ou seja, verificação de tipo em tempo de compilação.
P # 3) Quando o Java adicionou os genéricos?
Responda: Os genéricos foram adicionados ao Java em 2004 com o J2SE 5.0 com a intenção de garantir a segurança do tipo em tempo de compilação em Java.
P # 4) O que é um tipo genérico?
Responda: Um tipo genérico é uma classe, interface ou método genérico fornecido com um parâmetro de tipo. Isso permite a segurança de tipo e a reutilização do código.
P # 5) Podemos usar Genéricos com Array em Java?
Responda: Não. Java não permite matrizes genéricas.
Conclusão
Isso conclui o tutorial sobre os genéricos de Java, que é considerado um dos recursos mais importantes nas versões recentes do Java. O uso de Genéricos em programas Java garante segurança de tipo, bem como reutilização de código. Ele também garante a verificação em tempo de compilação para que o programa não seja interrompido durante a execução.
Os genéricos Java são úteis principalmente com a interface de coleções Java, que discutiremos em detalhes em outro tutorial desta série.
Leitura feliz!!
Leitura recomendada
- 15 melhores ferramentas JAVA para desenvolvimento, construção, criação de perfil, cobertura de código e revisão
- Tutorial do Java Collections Framework (JCF)
- DataTypes Java, Loops, Arrays, Switch e Assertions
- Implantação Java: Criação e execução de arquivo JAR Java
- Exceções Java e tratamento de exceções com exemplos
- Tutorial JAVA para iniciantes: mais de 100 tutoriais práticos em vídeo Java
- Tutorial de reflexão Java com exemplos
- Java 'this' Palavra-chave: Tutorial com exemplos de código