16.4 HERENCIA Y TIPOS COMODÍN

 

Llegamos al último post del bloque de Programación Genérica espero que os haya quedado claro, sino, pues ya sabéis que las dudas las podéis enviar a través de los comentarios del blog o escribiendo un correo a amizba@gmail.com

La herencia no funciona igual con las clases genéricas que con las clases ordinarias y este funcionamiento diferente nos va a obligar a utilizar tipos comodín sobre todo a la hora de llamar a métodos que han sido declarados dentro de una clase genérica.

Para ver la diferencia entre la herencia entre las clases ordinarias y las clases orgánicas hay que remontarse al apartado Todo Java:2.12 HERENCIA (empezandojava.blogspot.com) de la herencia en el que vimos un ejemplo el cual teníamos una clase llamada Empleado y una clase Jefe, la clase Jefe podía heredar de la clase Empleado utilizado el método sustitución, es decir, empleando la frase “Es un…” Un jefe es un empleado, sin embargo, la clase Empleado no puede heredar de la clase Jefe porque un empleado no siempre es un jefe.

Pues esto con las clases genéricas no funciona igual, si tenemos una clase de tipo genérico Empleado y otra clase de tipo genérico Jefe no existe relación de herencia para solucionar esto existen los tipos comodín.

Todo esto es mejor verlo sobre la práctica vamos a trabajar con cuatro clases algunas ya las hemos visto en apartados anteriores, la clase Pareja:

package clases_propias;

 

public class Pareja<T> {

     

      public Pareja() {

           

            primero = null;

           

           

      }

     

      public void setPrimero(T nuevoValor) {

           

            primero=nuevoValor;

      }

     

      public T getPrimero() {

           

            return primero;

      }

     

      private T primero;

 

}

HerenciaGenericos que es la que contiene el método principal main:

package clases_propias;

 

public class HerenciaGenericos {

 

      public static void main(String[] args) {

            // TODO Auto-generated method stub

 

      }

 

}

La clase Empleado:

package clases_propias;

 

public class Empleado {

     

      public Empleado(String nombre, int edad, double salario) {

           

            this.nombre=nombre;

           

            this.edad=edad;

           

            this.salario=salario;

           

      }

     

      public String dameDatos() {

           

            return "El empleado se llama "+nombre+" tiene "+edad+" años y tiene un salario de "+salario+" euros.";

      }

     

      private String nombre;

     

      private int edad;

     

      private double salario;

 

}

Y la clase Jefe:

package clases_propias;

 

public class Jefe extends Empleado{

     

      public Jefe(String nombre, int edad, double salario) {

           

            super(nombre, edad, salario);

      }

     

      double incentivo (double inc) {

           

            return inc;

      }

 

}

Nos vamos a la clase HerenciaGenericos y dentro del método main manejando la clase Empleado, la clase Jefe y el principio de sustitución “Es un…” podemos crear una instancia perteneciente a la clase Empleado y pasarle los parámetros:

package clases_propias;

 

public class HerenciaGenericos {

 

      public static void main(String[] args) {

           

            Empleado administrativa = new Empleado("Eva", 52, 12500);

 

      }

 

}

Creamos una instancia de la clase Jefe:

package clases_propias;

 

public class HerenciaGenericos {

 

      public static void main(String[] args) {

           

            Empleado administrativa = new Empleado("Eva", 52, 12500);

           

            Jefe director = new Jefe("Antonio", 25, 22500);

 

      }

 

}

Gracias al principio de sustitución “Es un…” podemos crear una variable de tipo Empleado y va a ser igual a director:

package clases_propias;

 

public class HerenciaGenericos {

 

      public static void main(String[] args) {

           

            Empleado administrativa = new Empleado("Eva", 52, 12500);

           

            Jefe director = new Jefe("Antonio", 25, 22500);

           

            Empleado nuevoEmpleado = director;

 

      }

 

}

Gracias a este principio un empleado puede ser un Jefe, esto es la herencia en Java.

Sin embargo, cuando son clases genéricas no es así como funciona la herencia. Con clases genéricas sería de la siguiente forma creamos la instancia Pareja de tipo Empleado al que le vamos a dar el nombre de administrativa:

package clases_propias;

 

public class HerenciaGenericos {

 

      public static void main(String[] args) {

           

            /*Empleado administrativa = new Empleado("Eva", 52, 12500);

           

            Jefe director = new Jefe("Antonio", 25, 22500);

           

            Empleado nuevoEmpleado = director;*/

           

            Pareja<Empleado> administrativa = new Pareja<Empleado>();

 

      }

 

}

Hacemos lo mismo pero con el tipo Jefe:

package clases_propias;

 

public class HerenciaGenericos {

 

      public static void main(String[] args) {

           

            /*Empleado administrativa = new Empleado("Eva", 52, 12500);

           

            Jefe director = new Jefe("Antonio", 25, 22500);

           

            Empleado nuevoEmpleado = director;*/

           

            Pareja<Empleado> administrativa = new Pareja<Empleado>();

           

            Pareja<Jefe> director = new Pareja<Jefe>();

 

      }

 

}

Si intentamos aplicar el principio de sustitución:

package clases_propias;

 

public class HerenciaGenericos {

 

      public static void main(String[] args) {

           

            /*Empleado administrativa = new Empleado("Eva", 52, 12500);

           

            Jefe director = new Jefe("Antonio", 25, 22500);

           

            Empleado nuevoEmpleado = director;*/

           

            Pareja<Empleado> administrativa = new Pareja<Empleado>();

           

            Pareja<Jefe> director = new Pareja<Jefe>();

           

            Pareja<Empleado> nuevoEmpleado = director;

 

      }

 

}

Vemos que nos marca un error:



Y si nos posicionamos con el puntero del ratón sobre el error:



No se puede convertir Pareja de tipo Jefe a Pareja de tipo Empleado. Vamos a ver cómo solucionarlo, vamos al código de la clase genérica Pareja y nos vamos a crear un método que nos imprima por consola un empleado en concreto.

      public static void imprimirTrabajador(Pareja<Empleado> p) {

           

           

      }

Le hemos pasado un objeto Pareja de tipo Empleado al que hemos llamado p. Lo que va a hacer este método es devolvernos el empleado:

      public static void imprimirTrabajador(Pareja<Empleado> p) {

           

            Empleado primero = p.getPrimero();

           

            System.out.println(primero);

           

      }

En la clase principal HerenciaGenericos vamos a llamar a este método para tipo Empleado y para tipo Jefe, si nos fijamos para el tipo Jefe da un error de compilación:



Esta es la restricción que hay en las clases genéricas utilizando el principio de sustitución. Si vemos el error nos lo indica claramente:



Para solucionar esto se utilizan los tipos comodín se usan de la siguiente forma, en el método si queremos que sea aplicable para la clase Empleado y sus subclases, por ejemplo, Jefe:

public static void imprimirTrabajador(Pareja<? extends Empleado> p) {

Donde le pasamos en el argumento dentro de los corchetes angulares la cláusula ? extends. Con esto y al guardar los cambios en Eclipse volvemos a la clase HerenciaGenericos y comprobamos que esa línea que nos marcaba error ya no nos lo marca.



Esto ha sido todo os espero en el próximo bloque, muchas gracias por seguirme y hasta pronto!

16.3 MÉTODOS GENÉRICOS << >> 17.1 INTRODUCCIÓN THREADS