Herencia
Introducción
Es uno de los pilares en los que se basa la orientación a objetos. Con la cual podremos crear una relación jerárquica entre clases. Es decir habrá clases “padre” o “base” y clases “hijos” o “derivadas”. Esto implica que habrá unas clases más genéricas y otras más específicas a partir de esas generales. ¿Cuando usaremos Herencia? Sobre todo hay dos enfoques:
- Cuando veamos que una clase es muy grande y que engloba muchas situaciones o diferentes estados en los objetos derivados, donde unos atributos o métodos se usen o no. Es muy probable que necesitemos clases hijas a partir de la clase padre. Estas clases hijas harán de especialización de la base. Supertipo -> Subtipos
- Si tenemos varias clases que se parecen en sí, y compartan métodos o atributos, implicará poder crear una clase padre de ellas. Esta clase padre unirá lo que tienen en común las clases hija. Subtipos -> Supertipo
La herencia nos permite crear jerarquías de clases en las que, a medida que descendemos por la misma se va refinando sus comportamientos (mayor especialización).
Por otro lado nos permite crear clases genéricas que defines rasgos comunes para una serie de clases.
La herencia nos permitirá crear arquitecturas O.O. de mayor calidad.
Implementación
Palabras reservadas: extends, super.
Para indicar que una clase hereda de otra , añadiremos la palabra reservada extends en su declaración con el nombre de la superclase. Ejemplo sencillo donde consideramos que la clase Alumno va a heredar de Persona:
class Persona {
String nombre;
int edad;
public void imprimePersona() {System.out.println("Datos personales: " + nombre + ", "+ edad );
}
}
class Alumno extends Persona{
char grupo;
}
class Unidad4 {
public static void main(String[] args) {
Persona p1 = new Persona();
p1.nombre="Elías";
p1.edad=5;
p1.imprimePersona();
Alumno a1= new Alumno();
a1.nombre="Román";
a1.edad=3;
a1.grupo='a';
a1.imprimePersona();
}
}
¿Qué se hereda? La subclase hereda todos los atributos y métodos de la superclase.
Consideraciones
- Atributos static también se heredan, a los static de una superclase se hereda el acceso ya que del miembro en sí no se hace una copia en la memoria del objeto.
- Una supeclase puede tener muchas subclases (las que queramos).
- Pero ojo! No hay herencia múltiple Java. Es decir una clase no puede tener dos padres. Sólo puede tener una superclase (exceptuando Java.lang.Object que por defecto todas las clases Java derivan de ello). Para solventar esa posible necesidad podemos usar Interface que veremos más adelante.
- Una subclase no puede acceder a un miembro private de su superclase.
- Cada vez que invoquemos un método, siempre se busca si está implementado o sobreescrito en la clase. Si no, se busca en el padre, y así sucesivamente hacia arriba hasta encontrarlo.
Constructores y super
En una jerarquía tanto las subclases como las superclases pueden tener sus propios constructores. En general, el constructor de la subclase invocará al constructor de la superclase, y posteriormente se encargará del resto de sus atributos en su propio constructor. La llamada al constructor “padre” se ejecuta antes que cualquier otra instrucción. Hay en general dos situaciones:
- Sino existe un constructor en la clase padre se ejecutará el constructor por defecto.
- Si hay varios constructores con parámetros en la clase padre, ¿cual se ejecutará?: Existe la instrucción super(lista_parametros): que nos permite ejecutar el constructor de la clase padre que queramos (en base a los parámetros…como siempre). Lo que tenemos que acordarnos es que sea la primera instrucción dentro del constructor de la clase hijo. Con los constructores se realiza una llamada en cadena. Ejemplo para que probeis herencia y el super:
public class Animal {
private int edad;
private String nombre;
@Override
public String toString() {
// TODO Auto-generated method stub
return super.toString();
}
public int getEdad() {
return edad;
}
public String getNombre() {
return nombre;
}
public void setEdad(int edad) {
this.edad = edad;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public Animal () {
System.out.println("Constructor de Animal");
}
public Animal (String nombre, int edad) {
System.out.println("Constructor de Animal");
this.setEdad(edad);
this.setNombre(nombre);
}
}
public class Perro extends Animal{
public String habla() {
return "guau!!";
}
public Perro () {
System.out.println("Constructor de Perro");
}
}
public class Gato extends Animal{
String habla() {
return "miauu!";
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "Gato:" + this.getNombre() + ":" + this.getEdad();
}
public Gato () {
System.out.println("Constructor de Gato");
}
public Gato (String nombre, int edad) {
super(nombre, edad);
System.out.println("Constructor de Gato");
}
}
public class Fauna {
public static void main(String[] args) {
Animal animal = new Animal();
System.out.println(animal);
animal.setNombre("Dude");
animal.setEdad(3);
System.out.println(animal);
Gato yin = new Gato();
yin.setEdad(2);
yin.setNombre("YinYang");
System.out.println(yin);
System.out.println(yin.habla());
Perro blob = new Perro();
blob.setEdad(5);
blob.setNombre("Blob");
System.out.println(blob);
System.out.println(blob.habla());
}
}
Modificador de acceso protected
No le doy mucha importancia a este modificador, pero con herencia es cuando implica ciertas limitaciones. Os dejo un enlace donde se explican las diferentes situaciones: enlace
Ejercicio 1
Un ordenador se caracteriza por su procesador(un String) y memoria RAM(un int). Los ordenadores pueden ser de sobremesa o portátiles. Para los ordenadores de sobremesa interesa su tipo de caja y para los portátiles su peso. Crea una jerarquía en java para la situación anterior y desde un main() crea un ordenador de sobremesa con la CPU y RAM que tu elijas y con caja de tipo “micro-atx”, lo mismo para un portátil de peso 1.5kg..
Ejercicio 2
Una persona se caracteriza por su dni, nombre y dirección. Queremos trabajar con dos tipos de personas: empleados y clientes. Los empleados son personas que además tienen un sueldo, los clientes son personas que además tienen una deuda. Crea una jerarquía en java para la situación anterior y desde un main() crea un empleado, un cliente y una persona genérica que no es ni empleado ni cliente. Imprime por pantalla los atributos de los objetos creados.
Ejercicio 3
Clases: Principal, Figura, Cuadrado, Circulo. Todas las clases en paquete por defecto.
Figura es superclase de las subclases Cuadrado y Circulo
la clase Figura:
-
atributo color(String) la clase Cuadrado:
-
atributo lado(double) la clase Circulo
-
atributo radio(double)
Todos los atributos son de acceso privado. Utiliza los set/get estrictamente necesarios. Los constructores permiten crear Cuadrados y Circulos indicando su color e indicando la longitud del lado (caso cuadrado) o la longitud del radio (caso Circulo).
En main() de clase Principal:
class Principal{
public static void main(String[] args) {
Cuadrado miCuadrado=new Cuadrado(2.5,"azul");
System.out.println("Lado de miCuadrado: "+ miCuadrado.getLado());
Circulo miCirculo=new Circulo(3.6,"blanco");
System.out.println("Color de miCirculo: "+ miCirculo.getColor());
}
}
Ejercicio 4
Escribe la siguiente jerarquía:
- superclase Persona y subclases: Hombre y Mujer
- la clase Persona: atributo edad
- la clase Hombre: atributo boolean hizoMili
- la clase Mujer: atributo boolean fueMadre
La jerarquía anterior debe de pertenecer al paquete personas
La clase Unidad4 pertenece al paquete por defecto Todos los atributos son de acceso privado.
Los constructores permiten crear Hombres y mujeres indicando su edad e indicando si hizo la mili (caso hombres) o si fue madre (caso mujeres). Si la edad que se indica en el constructor es mayor de 65, el programa inicia este atributo con el valor 65. Utiliza los set/get estrictamente necesarios. El main() debe ser obligatoriamente el siguiente:
public static void main(String[] args) {
Hombre carmelo=new Hombre(85,true);
Mujer telma=new Mujer(21,false);
System.out.println("Edad Carmelo: "+ carmelo.getEdad() +" Hizo mili Carmelo: "+ carmelo.isHizoMili());
System.out.println("Edad Telma: "+ telma.getEdad() +" Fue madre Telma: "+ telma.isFueMadre());
}
Y genera:
Edad Carmelo: 65 Hizo mili Carmelo: true
Edad Telma: 21 Fue madre Telma: false