Programación Orientada a
Objetos en Java
Sesión 9: Herencia
Motivación
•
Hasta ahora escribíamos clases para modelar objetos
mediante la agrupación de propiedades de tipos
básicos o complejos (otras clases)
•
Pero, ¿qué hacemos en los siguientes casos?
–
Queremos crear diferentes clases que comparten algo más
que el conjunto de métodos especificado por un interface
común
–
Queremos crear objetos que son un caso particular de los
definidos por una clase existente
•
Porque hacen más cosas
Clases que comparten algo más que un interface
•
Vehículos
–
Avión (Tiene
matricula
y vuela)
–
Barco (Tiene
matrícula
y navega)
–
Coche (Tiene
matrícula
y circula)
•
Mamíferos
–
Delfín (Tiene
pelo y mamas
, y nada)
–
Mono (Tiene
pelo y mamas
, y trepa)
–
Murciélago (
Tiene pelo y mamas
, y vuela)
•
Figuras Cerradas
–
Circulo (Tiene
coordenadas
, radio y se puede dibujar y mover)
–
Estrella (Tiene
coordenadas
, número de brazos, y se puede dibujar y mover)
•
Publicación
–
Libro (Tiene
título, número de páginas
y autor)
–
Cómic (Tiene
título, número de páginas
, guionista e Ilustrador)
–
Periódico (Tiene
título, número de páginas
y fecha)
Clases que son ampliaciones de otras
•
Personaje (Tiene nombre y saluda)
–
Guerrero (Personaje + lucha)
–
Mago (Personaje + hechizar)
•
Pez (Tiene nombre y nada)
–
Tiburón (Pez + ataca)
–
Volador (Pez + vuela)
•
Esfera (tiene radio, volumen)
–
Bola de Billar (Esfera + color, posición, velocidad)
–
Planeta (Esfera + nombre, órbita)
Herencia
•
Técnica que permite crear clases a partir de otras para
ampliar o modificar la estructura y/o funcionalidad de las ya
existentes
Persona
Cadena
Fecha
Entero
Entero
Entero
Persona
Empleado
Entero
Agregación
de Miembros
(tiene)
Herencia (es un)
Clase padre o
clase base
Clase hija o
subclase
•
Atributos: x,y, radio
•
Método: mueve, pinta
•
Atributos: x,y, brazos
•
Método: mueve, pinta
Heredar para agrupar
•
Dos clases muy parecidas en cuanto a “qué” hacen y “cómo”
lo hacen son candidatas a heredar de una clase común donde
se define el “qué” y el “cómo” compartidos por ambas
Circulo
Estrella
•
Atributos: x,y
•
Métodos: mueve
Figura
•
Atributo: radio
•
Método: pinta
•
•
Atributo: brazos
Método: pinta
Circulo
Estrella
Ej: Tanto Circulo como Estrella
comparten los atributos de posición y
la posibilidad de ser desplazadas por
el plano, pero cada uno se define y se
pinta de una forma concreta y
específica
Heredar para ampliar
•
En muchas ocasiones necesitamos clases nuevas que tienen
en común algo con otra existente
•
Atributos: radio
•
Métodos: volumen
Esfera
•
Atributos: color, posicion,
velocidad
•
Método: mueve
•
Atributos: nombre,
órbita
•
Método: rota
BolaBillar
Planeta
Ej: Cada subclase recibe los atributos
y métodos del padre, pero cada una
los amplía de una forma particular
•
Creamos las subclases
Herencia en Java
•
Se usa la palabra
extends
•
Automáticamente se heredan todos los miembros y métodos
excepto los constructores
•
Se pueden tener múltiples hijos
–
Varias clases pueden heredar de la misma clase padre
•
Sólo se puede tener un padre
Ejemplo
V1.0
public class Circulo { private double x,y; private double radio; public Circulo(double x, double y, double radio) { this.x = x; this.y = y; this.radio = radio; }
// Métodos get y set public void dibuja() { ... } }
public class Estrella { private double x,y; private int brazos; public Estrella(double x, double y, int brazos) { this.x = x; this.y = y; this.brazos = brazos; }
// Métodos get y set
public void dibuja() { ... } }
public class Figura { private double x,y;
public Figura(double x, double y) { this.x = x;
this.y = y; }
public void setX(double d) { this.x = d; } public double getX() { return x; }
public void setY(double d) { this.y = d; } public double getY() { return y; } }
extends Figura { extends Figura {
¿Error?
Herencia
y Visibilidad
•
Los miembros y métodos privados de las clases ancestras no
son visibles para las subclases
•
Los públicos sí
•
Para hacer un miembro/método privado para cualquier clase
excepto para las que sean subclases se usa el modificador
Ejemplo
V2.0
public class Circulo extends Figura { private double radio;
public Circulo(double x, double y, double radio) { this.x = x; this.y = y; this.radio = radio; }
public void dibuja() { ... } }
public class Estrella extends Figura { private int brazos;
public Estrella(double x, double y, int brazos) { this.x = x; this.y = y; this.brazos = brazos; }
public void dibuja() { ... } }
public class Figura { protected double x,y;
public Figura(double x, double y) { this.x = x;
this.y = y; }
public void setX(double d) { this.x = d; } public double getX() { return x; } public void setY(double d) { this.y = d; } public double getY() { return y; } }
¿Siempre
posible?
Herencia y Constructores
•
Los constructores no se heredan
•
Los objetos de una subclase tienen sus miembros y los
heredados pero sólo puede acceder a los públicos y
protegidos
•
Al crear un objeto hay que inicializar todos los miembros, los
propios y los heredados, pero no todos los heredados son
públicos o protegidos por lo que no siempre podemos hacerlo
•
Es necesario poder invocar al constructor de la clase padre
para inicializar los miembros privados heredados
Uso de super
•
Invoca al constructor del padre (ancestro directo)
•
Se pueden pasar parámetros
•
Según los parámetros se invoca a un constructor u otro del
padre
•
Restricciones
–
Sólo una llamada
–
Sólo dentro de los constructores
–
Siempre en la primera línea del constructor
Ejemplo
V3.0
public class Circulo extends Figura { private double radio;
public Circulo(double x, double y, double radio) { super(x,y); this.radio = radio; }
public void dibuja() { ... }
public class Estrella extends Figura { private int brazos;
public Estrella(double x, double y, int brazos) { super(x,y); this.brazos = brazos; }
public class Figura { protected double x,y;
public Figura(double x, double y) { this.x = x; this.y = y;
}
public void setX(double d) { this.x = d; } public double getX() { return x; } public void setY(double d) { this.y = d; } public double getY() { return y; } }
Constructores implícitos
•
Reglas
–
Si no ponemos constructor las clases incluyen uno implícito sin
parámetros
–
Los constructores implícitos invocan automáticamente al constructor
implícito de su clase padre
–
Si en un constructor no se usa super, Java incluye automáticamente
un super() para invocar al constructor implícito de la clase padre
•
Consecuencias
–
Si la clase padre no tiene constructor implícito (o uno sin parámetros)
las clases derivadas deben tener algún constructor en el que se haga
un super válido, de lo contrario se produce error de compilación
Ejemplo
public class Hijo2 extends Padre { private double miembroHijo2; public Hijo2(double d) { this.miembroHijo2 = d; }
} public class Padre {
private double miembroPadre; public Padre(double d) { this.miembroPadre = d; }
}
public class Hijo1 extends Padre { public void metodo () { ... } }
Herencia y polimorfismo
•
Los objetos de clases descendientes son de hecho objetos de
su clase padre (y demás ancestros)
•
La herencia da lugar a una jerarquía de tipos de datos
class Test {
public static void main(String args[]) { Figura f = null;
Circulo sol = new Circulo(0,0, 2); Estrella polar = new Estrella(10,10, 5); sol.setX(10);
polar.setY(20); f = polar; f.setX(10);
if (f instanceof Estrella) { Estrella aux = (Estrella)f; int b = aux.getNumeroBrazos(); }
} }
La superclase Object
•
Java incluye una enorme biblioteca de clases organizadas de
forma jerárquica
•
La clase
Object
encabeza esta jerarquía
•
Object
es padre de todos las clases de forma directa o
indirecta, cualquier clase que no herede de ninguna será
descendiente directo de
Object
de forma automática
•
Por ser padre de todas siempre podemos usar variables de
tipo
Object
para almacenar referencias a otros objetos. Al
hacerlo perdemos el tipo aunque lo podremos recuperar
usando
instanceof
y un casting
Ejemplo de uso de Object
class Test {public static void main(String args[]) { Object objeto = new Circulo(0,0, 5); Object logo[] = new Object[2]; logo[0] = new Circulo(0,0, 10); logo[1] = new Estrella(0,0, 3); if (objeto instanceof Circulo) { Circulo aux = (Circulo)objeto; System.out.println(aux.getRadio()); }
if (logo[1] instanceof Estrella) { Estrella aux = (Estrealla)logo[1];
System.out.println(aux.getBrazos()); } Figura f = (Figura)objeto; f.setX(f.getX()+5); f = (Figura)logo[1]; f.setY(f.getY()-5); } }