viernes, 19 de junio de 2020

Clases genéricas

Java Generics

Java permite que los programadores puedan crear clases, interfaces y métodos en los que el tipo de datos sobre los que operan se especifica como parámetro. Es decir, de tipos parametrizados.

A estos se les denomina genéricos. Por ejemplo, una clase que maneja estos parámetros se denomina clase genérica, igualmente será con un método o interfaz.

Un método genérico debe ser declarado dentro de una clase o interfaz genérica. Para ello, empleamos la siguiente sintaxis:
   // Clase genérica
   public class Generico<T>

   //Interfaz genérica
   public interface Generico<T,E>

La ventaja del código que emplea estos métodos es que funcionará automáticamente con el tipo de datos pasados a su parámetro de tipo.
   // Instanciación de la clase genérica
   Generico<String> gen = new Generico<>();
   // En este caso el tipo de dato es un String


Estos algoritmos son muy útiles para y se emplean muchísimo en las bibliotecas internas de Java como en las Colecciones o métodos de ordenamiento rápido.

Clase genérica simple- Código

Declaramos el tipo genérico T y un atributo de ese tipo llamado "atributo"
  1. package clases;
  2. public class Generico<T> {
  3. private T atributo;
  4. public Generico(T atributo) {
  5. this.atributo = atributo;
  6. }
  7. public String getClase() {
  8. return String.format("Clase: %s", this.atributo.getClass().getName());
  9. }
  10. public String getAtributo() {
  11. return String.format("Contenido: %s", this.atributo.toString());
  12. }
  13. }

Prueba y resultado

Al crear objetos de estas clases genéricas podemos emplear 3 formas:
  • Indicar dentro de la sintaxis diamante el tipo
  • Usar el tipo desconocido ?, el constructor recibe el tipo de parámetro
  • Obviar el tipo, el constructor recibe el parámetro y usa su tipo.
  1. package test;
  2. import clases.ContenedorGenerico;
  3. import clases.Generico;
  4. import clases.Operador;
  5. public class Test {
  6. public static void main(String[] args) {
  7. Generico<String> gen1 = new Generico<>("Hola");
  8. System.out.println(gen1.getClase());
  9. System.out.println(gen1.getAtributo());
  10. Generico<?> gen2 = new Generico(45d);
  11. System.out.println(gen2.getClase());
  12. System.out.println(gen2.getAtributo());
  13. Generico gen3 = new Generico(true);
  14. System.out.println(gen3.getClase());
  15. System.out.println(gen3.getAtributo());
  16. }
  17. }

Clase: java.lang.String
Contenido: Hola

Clase: java.lang.Double
Contenido: 45.0

Clase: java.lang.Boolean
Contenido: true


Clase genérica con varios parámetros - Código

Podemos indicar más de un tipo genérico, estos van separados por comas.
  1. package clases;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. public class ContenedorGenerico<E,F> {
  5. private Map<E, F> contenedor;
  6. public ContenedorGenerico() {
  7. this.contenedor = new HashMap<>();
  8. }
  9. public void agregar(E clave, F valor) {
  10. this.contenedor.put(clave, valor);
  11. }
  12. public Map<E, F> getContenedor() {
  13. return this.contenedor;
  14. }
  15. }

Prueba y resultado

Las colecciones emplean internamente las clases y métodos genéricos.
  1. package test;
  2. import clases.ContenedorGenerico;
  3. import clases.Generico;
  4. import clases.Operador;
  5. public class Test {
  6. public static void main(String[] args) {
  7. ContenedorGenerico<Integer,String> contenedor = new ContenedorGenerico<>();
  8. contenedor.agregar(12, "doce");
  9. contenedor.agregar(11, "once");
  10. contenedor.agregar(10, "diez");
  11. contenedor.getContenedor().forEach((k,v)->{
  12. System.out.println("Clave: "+k);
  13. System.out.println("Valor: "+v);
  14. });
  15. }
  16. }

Clave: 10
Valor: diez

Clave: 11
Valor: once

Clave: 12
Valor: doce


Clase genérica con parámetros limitados - Código

Para limitar el tipo de datos que se pueden recibir se utiliza la palabra reservada "extends" y luego la superclase. Por ejemplo, el siguiente código muestra una clase que solo permite tener parámetros de tipo numéricos.
  1. package clases;
  2. public class Operador<A extends Number, B extends Number> {
  3. A valorA;
  4. B valorB;
  5. public Operador(A valorA, B valorB) {
  6. this.valorA = valorA;
  7. this.valorB = valorB;
  8. }
  9. public Double getSuma() {
  10. return this.valorA.doubleValue() + this.valorB.doubleValue();
  11. }
  12. public Double getProducto() {
  13. return this.valorA.doubleValue() * this.valorB.doubleValue();
  14. }
  15. }

Prueba y resultado

  1. package test;
  2. import clases.ContenedorGenerico;
  3. import clases.Generico;
  4. import clases.Operador;
  5. public class Test {
  6. public static void main(String[] args) {
  7. Operador op1 = new Operador(4, 5);
  8. System.out.println("Suma: " + op1.getSuma());
  9. System.out.println("Producto: " + op1.getProducto());
  10. Operador op2 = new Operador(4.6, 5);
  11. System.out.println("Suma: " + op2.getSuma());
  12. System.out.println("Producto: " + op2.getProducto());
  13. Operador op3 = new Operador(2.5, 1.65);
  14. System.out.println("Suma: " + op3.getSuma());
  15. System.out.println("Producto: " + op3.getProducto());
  16. }
  17. }

Suma: 9.0
Producto: 20.0

Suma: 9.6
Producto: 23.0

Suma: 4.15
Producto: 4.125


No hay comentarios:

Publicar un comentario