Genéricos significa tipos parametrizados . La idea es permitir que el tipo (entero, string, etc., y tipos definidos por el usuario) sea un parámetro para métodos, clases e interfaces. Utilizando Generics, es posible crear clases que trabajen con diferentes tipos de datos. Una entidad como clase, interfaz o método que opera en un tipo parametrizado es una entidad genérica.
¿Por qué genéricos?
El Objeto es la superclase de todas las demás clases, y la referencia de Objeto puede referirse a cualquier objeto. Estas características carecen de seguridad de tipo. Los genéricos agregan ese tipo de característica de seguridad. Discutiremos ese tipo de característica de seguridad en ejemplos posteriores.
Los genéricos en Java son similares a las plantillas en C++. Por ejemplo, clases como HashSet, ArrayList, HashMap, etc., usan genéricos muy bien. Existen algunas diferencias fundamentales entre los dos enfoques de los tipos genéricos.
Tipos de genéricos de Java
Método genérico: el método genérico de Java toma un parámetro y devuelve algún valor después de realizar una tarea. Es exactamente como una función normal, sin embargo, un método genérico tiene parámetros de tipo que son citados por el tipo real. Esto permite utilizar el método genérico de una manera más general. El compilador se ocupa del tipo de seguridad que permite a los programadores codificar fácilmente, ya que no tienen que realizar largas conversiones de tipos individuales.
Clases genéricas: una clase genérica se implementa exactamente como una clase no genérica. La única diferencia es que contiene una sección de parámetros de tipo. Puede haber más de un tipo de parámetro, separados por una coma. Las clases que aceptan uno o más parámetros se conocen como clases parametrizadas o tipos parametrizados.
Clase genérica
Al igual que C++, usamos <> para especificar tipos de parámetros en la creación de clases genéricas. Para crear objetos de una clase genérica, usamos la siguiente sintaxis.
// To create an instance of generic class BaseType <Type> obj = new BaseType <Type>()
Nota: En el tipo de parámetro no podemos usar primitivas como ‘int’, ‘char’ o ‘double’.
Java
// Java program to show working of user defined // Generic classes // We use < > to specify Parameter type class Test<T> { // An object of type T is declared T obj; Test(T obj) { this.obj = obj; } // constructor public T getObject() { return this.obj; } } // Driver class to test above class Main { public static void main(String[] args) { // instance of Integer type Test<Integer> iObj = new Test<Integer>(15); System.out.println(iObj.getObject()); // instance of String type Test<String> sObj = new Test<String>("GeeksForGeeks"); System.out.println(sObj.getObject()); } }
15 GeeksForGeeks
También podemos pasar múltiples parámetros de tipo en clases genéricas.
Java
// Java program to show multiple // type parameters in Java Generics // We use < > to specify Parameter type class Test<T, U> { T obj1; // An object of type T U obj2; // An object of type U // constructor Test(T obj1, U obj2) { this.obj1 = obj1; this.obj2 = obj2; } // To print objects of T and U public void print() { System.out.println(obj1); System.out.println(obj2); } } // Driver class to test above class Main { public static void main (String[] args) { Test <String, Integer> obj = new Test<String, Integer>("GfG", 15); obj.print(); } }
GfG 15
Funciones genéricas:
También podemos escribir funciones genéricas que se pueden llamar con diferentes tipos de argumentos según el tipo de argumentos pasados al método genérico. El compilador maneja cada método.
Java
// Java program to show working of user defined // Generic functions class Test { // A Generic method example static <T> void genericDisplay(T element) { System.out.println(element.getClass().getName() + " = " + element); } // Driver method public static void main(String[] args) { // Calling generic method with Integer argument genericDisplay(11); // Calling generic method with String argument genericDisplay("GeeksForGeeks"); // Calling generic method with double argument genericDisplay(1.0); } }
java.lang.Integer = 11 java.lang.String = GeeksForGeeks java.lang.Double = 1.0
Los genéricos solo funcionan con tipos de referencia:
Cuando declaramos una instancia de un tipo genérico, el argumento de tipo pasado al parámetro de tipo debe ser un tipo de referencia. No podemos usar tipos de datos primitivos como int , char.
Test<int> obj = new Test<int>(20);
La línea anterior da como resultado un error de tiempo de compilación que se puede resolver usando contenedores de tipo para encapsular un tipo primitivo.
Pero las arrays de tipo primitivo se pueden pasar al parámetro de tipo porque las arrays son tipos de referencia.
ArrayList<int[]> a = new ArrayList<>();
Los tipos genéricos difieren según sus argumentos de tipo:
Considere el siguiente código Java.
Java
// Java program to show working // of user-defined Generic classes // We use < > to specify Parameter type class Test<T> { // An object of type T is declared T obj; Test(T obj) { this.obj = obj; } // constructor public T getObject() { return this.obj; } } // Driver class to test above class Main { public static void main(String[] args) { // instance of Integer type Test<Integer> iObj = new Test<Integer>(15); System.out.println(iObj.getObject()); // instance of String type Test<String> sObj = new Test<String>("GeeksForGeeks"); System.out.println(sObj.getObject()); iObj = sObj; // This results an error } }
Producción:
error: incompatible types: Test cannot be converted to Test
Aunque iObj y sObj son de tipo Test, son las referencias a diferentes tipos porque sus parámetros de tipo difieren. Los genéricos agregan seguridad de tipo a través de esto y evitan errores.
Parámetros de tipo en los genéricos de Java
Las convenciones de nomenclatura de parámetros de tipo son importantes para aprender a fondo los genéricos. Los parámetros de tipo comunes son los siguientes:
- T-Tipo
- E – Elemento
- K – Clave
- N – Número
- V-Valor
Ventajas de los genéricos:
Los programas que usan Generics tienen muchos beneficios sobre el código no genérico.
1. Reutilización de código: podemos escribir un método/clase/interfaz una vez y usarlo para cualquier tipo que queramos.
2. Seguridad de tipos: los genéricos cometen errores que aparecen en tiempo de compilación que en tiempo de ejecución (siempre es mejor conocer los problemas en su código en tiempo de compilación en lugar de hacer que su código falle en tiempo de ejecución). Suponga que desea crear una ArrayList que almacene el nombre de los estudiantes, y si por error el programador agrega un objeto entero en lugar de una string, el compilador lo permite. Pero, cuando recuperamos estos datos de ArrayList, causa problemas en tiempo de ejecución.
Java
// Java program to demonstrate that NOT using // generics can cause run time exceptions import java.util.*; class Test { public static void main(String[] args) { // Creatinga an ArrayList without any type specified ArrayList al = new ArrayList(); al.add("Sachin"); al.add("Rahul"); al.add(10); // Compiler allows this String s1 = (String)al.get(0); String s2 = (String)al.get(1); // Causes Runtime Exception String s3 = (String)al.get(2); } }
Producción :
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at Test.main(Test.java:19)
¿Cómo resuelven los genéricos este problema?
Al definir ArrayList, podemos especificar que esta lista solo puede tomar objetos String.
Java
// Using Java Generics converts run time exceptions into // compile time exception. import java.util.*; class Test { public static void main(String[] args) { // Creating a an ArrayList with String specified ArrayList <String> al = new ArrayList<String> (); al.add("Sachin"); al.add("Rahul"); // Now Compiler doesn't allow this al.add(10); String s1 = (String)al.get(0); String s2 = (String)al.get(1); String s3 = (String)al.get(2); } }
Producción:
15: error: no suitable method found for add(int) al.add(10); ^
3. No se necesita la conversión de tipo individual: si no usamos genéricos, entonces, en el ejemplo anterior, cada vez que recuperamos datos de ArrayList, tenemos que encasillarlos. El encasillamiento en cada operación de recuperación es un gran dolor de cabeza. Si ya sabemos que nuestra lista solo contiene datos de strings, no necesitamos encasillarlos cada vez.
Java
// We don't need to typecast individual members of ArrayList import java.util.*; class Test { public static void main(String[] args) { // Creating a an ArrayList with String specified ArrayList<String> al = new ArrayList<String>(); al.add("Sachin"); al.add("Rahul"); // Typecasting is not needed String s1 = al.get(0); String s2 = al.get(1); } }
4. Los genéricos promueven la reutilización del código: con la ayuda de los genéricos en Java, podemos escribir código que funcionará con diferentes tipos de datos. Por ejemplo,
public <T> void genericsMethod (T data) {...}
Aquí, hemos creado un método genérico. Este mismo método se puede utilizar para realizar operaciones en datos enteros, datos de string, etc.
5. Implementación de algoritmos genéricos: mediante el uso de genéricos, podemos implementar algoritmos que funcionan en diferentes tipos de objetos y, al mismo tiempo, también son seguros para los tipos.
Este artículo es una contribución de Dharmesh Singh . Si le gusta GeeksforGeeks y le gustaría contribuir, también puede escribir un artículo y enviarlo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks. Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.
Publicación traducida automáticamente
Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA