Jerarquía de Clases: Herencia, Composición
y Polimorfismo
Programación II
Dr. Javier Nieves Acedo
Este tema es
“la clave”…
… es el
poder de la POO …
… para hacer lo que
queramos…
… incluso algo
mejor…
…
;-)…
… o más
divertido…
… pero usando
jerarquias…
Herencia (1)
 Hay una relación de herencia entre clases
cuando se cumple la frase “es un”:
Vehículo
“ES UN”
Coche
Camión
Moto
Herencia (2)
 Cuando se realiza una herencia
(generalización) se obtienen los atributos y
los métodos miembros de la clase padre.
Clase Atributo Declaración
A
dato a
A a1;
Representación
a
B
dato b
B b1;
b
c
C
dato c
C c1;
Herencia (3)
 Tipos de Herencia:
 Herencia Simple: una clase base o padre
 Herencia Múltiple: más de una clase base o
padre.
 Java únicamente permite herencia simple pero
provee un mecanismos para simularla.
 Otros lenguajes soportan la herencia múltiple
(C++)
Herencia (4)
 Los métodos y los atributos se heredan hacia
abajo en la jerarquía.
 En Java, todas las clases derivan de la clase
Object.
 Las clases superiores describen un
comportamiento más general. Las inferiores
más específico.
Herencia (5)
 Las clases hijas heredan (tienen) todos los atributos
o métodos de la clase superior
 Solo puede acceder a los que no sean privados
 La solución actual es poner todo a public
 No se trata de la solución óptima
 Como implementarla:
public class <nombreClase> extends
<nombreClaseBase> {
…
}
Herencia (6)
 Las clases base deben ser accesibles:
 Estar en el mismo paquete.
 Estar declarada en otro paquete como public.
 No estar declarada como final
 La relación de herencia es trnsitiva
 A  B, B  C, entonces, A C
 Si no hay clausula extends, la clase hereda de
java.lang.object
Herencia (7)
 Ejemplo (1):
public class Persona {
public String nombre;
public String direccion;
public long telefono;
public Persona() {…}
public Persona pedirDatosPersona() {…}
}
Herencia (8)
 Ejemplo (2):
Public class Empleado extends Persona {
public int antiguedad;
public int categoria;
public int testAntig() {…}
}
¿Qué atributos y métodos tiene la clase
Empleado?
Herencia (7)
 Los constructores no se heredan.
 En la practica:
 No se generan objetos de la clase base.
 Está para proporcionar el formato común.
Herencia (7)
 Ventajas
 Reutilización de código
 Diferenciación de código (menos cláusulas
if)
Herencia (8)
 Consideraciones al heredar
 Los atributos son todos nuevos
 Si se repite algún nombre, se oculta el del padre
 Sigue existiendo pero no se puede acceder
directamente.
 Se puede acceder a través de métodos
 No es recomendable
Herencia (9)
 Consideraciones al heredar
 Los métodos son nuevos o modificados
 Override  Redefinición del método
 Los métodos modificados deben
 Respetar la cabecera (sino es nuevo)
 No pueden bajar la visibilidad, sí subirla
o private  [], protected, public
o []  protected, public
o protected  public
Herencia (10)
 Consideraciones al heredar
 static
 Los atributos estáticos del padre se pueden usar
pero no se heredan.
 Los métodos estáticos del padre se pueden usar
pero no se heredan.
 Los constructores nunca se heredan, las clases
deben definir los suyos propios.
… la herencia parece
fantástica…
… pero nos estamos
saltando…
… la
encapsulación…
… y la
solución es …
Acceso abstract
(1)
 Sirve para proporcionar comportamiento
común a varias clases.
 Indica que es una clase incompleta.
 La clase puede (no es obligatorio) tener algunos
métodos declarados pero no implementados.
 Las clases con este modificador no pueden
instanciarse.
Acceso abstract
(2)
 Ejemplo:
abstract class Punto
//clase abstracta
{
int x;
int y;
void mover(int x, int y)
{
this.x += x; this.y += y;
}
abstract void dibujar();
//método abstracto
}
abstract class PuntoColoreable extends Punto
{
int color;
}
class PuntoSimple extends Punto
{
void dibujar()
{
System.out.println(“(”+ x + ”,” + y + ”)”);
}
}
Acceso abstract
(3)
 Un método abstracto es el que no tiene
implementación (diferente a vacío).
Método Abstracto
Abstract class X {
abstract void m1();
}
Método Vacío
class X {
void m1(){ }
}
 Una clase que contiene un método abstracto es
abstracta y debemos ponerle el modificador de
abstracto.
Acceso abstract
(4)
 Cuando una clase hereda un método abstracto
puede…
 Implementar el método (darle código)
 No implementarlo y se mantiene la clase como
abstracta.
 Una clase es abstracta si
 Tiene un método abstracto
 Hereda un método abstracto y no lo implementa
Acceso abstract
(4)
 Utilidad de los métodos abstractos
 Las clases abstractas definen como tienen que
comportarse las hijas, métodos obligatorios.
 Indica el comportamiento pero no
compromete a un comportamiento en
concreto.
 Pueden existir métodos que no sean
abstractos porque sí que se puede definir.
Acceso final
 Indica que la definición de la clase está
completa.
 No se puede heredar (no puede tener
subclases).
 Si una clase se declara como abstract y final,
error de compilación.
Acceso public
 La clase es accesible por clases de otros
paquetes.
 Solo una clase public por fichero de código
fuente.
 Las otras clases, si las hubiera, serían privadas.
Acceso protected (1)
 No es bueno perder la ocultación de
métodos y atributos privados para hacer una
generalización.
 Existe otro modo de acceso que solo tiene
sentido en relaciones de herencia o
generalización.
 Atributos y Métodos accesibles por las
clases hijas y el mismo paquete.
Acceso protected (2)
 Ejemplo:
public class Base1 {
int a; // Sin modificador. Disponibles
int b; // a la clase y las del mismo paquete.
protected int c; // Disponibles solo a la propia
// clase, el paquete,
protected int d; // y a las clases derivadas.
public int e; // Disponibles a todas las
// clases y el paquete, así como
public int f; // a otras partes del programa.
}
Acceso protected (3)
 Las clases base no suelen tener miembros
privados
 Las clases hijas necesitan acceder a sus
elementos
… ahora los constructores
son más importantes …
Constructores y Herencia (1)
 Los constructores no se heredan
 Hay que estudiar su funcionamiento
 Hasta ahora, pasos del constructor:
 Crea el objeto, reserva espacio y conecta
nombre y memoria
 Ejecuta instrucciones
 Pero esta forma puede dar problemas…
Revisemos la cadena de
constructores
Constructores y Herencia (2)
 IMPORTANTE:
 El constructor de una clase derivada no puede
construirse hasta que se construya a su padre
 Cada constructor inicializa sus atributos
 Primero los padres
Constructores y Herencia (3)
 Si hay mas de una generalización, la clase se
preocupa de crear el padre más cercano
Clase Base
A
construye a su padre
Clase Derivada
B
construye a su padre
Clase Derivada
C
Constructores y Herencia (4)
 El constructor de la clase derivada tiene que
utilizar el método super(…) para construir
a su padre.
 Si el programador no lo hace, Java llama
automáticamente al método super()
Referencias this y super (1)
 this:
 Referencia a la propia instancia con la que se está
trabajando.
 No hace falta usarla para acceder a los métodos o
atributos de instancia.
 A veces es necesaria su utilización
 Desambiaguación de términos
 Pasar la referencia del propio objeto:

panel.dibujaObjeto(this);
Referencias this y super (2)
 super:
 Permite referenciar a la clase padre.
 Se emplea cuando se ha definido un método y
se quiere acceder al método del padre (sino se
llamaría al de la clase).
 Permite llamar al constructor de la clase
padre desde la clase hija. Esta llamada debe ser
la primera del constructor hijo.
Referencias this y super (3)
class Rectangulo
{
public ublic void saludar()
{
System.out.println("Hola, soy Rectangulo, y saludo");
}
}
class Cuadrado extends Rectangulo
{
public void saludar()
//Método redefinido
{
System.out.println(“Hola, soy un cuadrado”);
}
public void saludos()
{
saludar();
//Hola, soy un cuadrado
this.saludar();
//Hola, soy un cuadrado
super.saludar(); //Hola, soy Rectangulo, y saludo
}
public static void main (String[] args)
{
Cuadrado c1 = new Cuadrado();
c1.saludos();
}
}
… pero hay otras
relaciones …
Composición (1)
 Hay una relación de composición entre
clases cuando se cumple la frase “tiene un”:
Vehículo
“TIENE UN”
Motor
Chasis
Carrocería
Composición (2)
 Los constructores y destructores son
importantes en las relaciones de
composición:
 No se puede construir un objeto hasta que
están construidos todos los que lo
componen
Composición (3)
 Pautas de construcción (1):
 Constructor de la clase recibe todo lo
necesario para crear todas las clases.
 El compilador construye primero los
miembros y luego el contenedor
Composición
(5)
 Pautas de construcción (2):
 La clase compuesta no puede acceder a los
miembros privados de las clases que la
componen.
 Para evitar un paso excesivo de parámetros se
pueden crear los objetos y pasarlos como
parámetros a la clase compuesta
Composición
(6)
class Persona {
Persona padre;
//Atributo de tipo clase
String nombre;
public Persona(Persona pPadre, String pNombre)
{
padre = pPadre; nombre = pNombre;
}
public String saluda()
{
return nombre;
}
public Persona getPadre()
{
return padre;
}
public static void main (String args[])
{
Persona filiberto = new Persona(null,"Filiberto");
Persona pablo = new Persona( filiberto, "Pablo" );
Persona nuria = new Persona( filiberto, "Nuria" );
Persona alberto = new Persona( nuria, "Alberto" );
//El nieto es Alberto
System.out.println("El nieto es: " + alberto.saluda());
//La madre es Nuria
System.out.println("La madre: " + alberto.getPadre().saluda());
//El abuelo es Filiberto
System.out.println("El abuelo es: " + alberto.getPadre().getPadre().saluda());
}
}
Composición
(7)
class Persona {
Persona padre;
//Atributo de tipo clase
String nombre;
public Persona(Persona pPadre, String pNombre)
{
padre = pPadre; nombre = pNombre;
}
public String saluda()
{
return nombre;
}
public Persona getPadre()
{
return padre;
}
public static void main (String args[])
{
Persona filiberto = new Persona(null,"Filiberto");
Persona pablo = new Persona( filiberto, "Pablo" );
Persona nuria = new Persona( filiberto, "Nuria" );
Persona alberto = new Persona( nuria, "Alberto" );
//El nieto es Alberto
System.out.println("El nieto es: " + alberto.saluda());
//La madre es Nuria
System.out.println("La madre: " + alberto.getPadre().saluda());
//El abuelo es Filiberto
System.out.println("El abuelo es: " + alberto.getPadre().getPadre().saluda());
}
}
Composición
(8)
 Error de referencia nula:
class Fecha {
private int dia, mes, anyo;
class Persona {
private String nombre;
private Fecha fechaNcto; //COMPOSICIÓN
Fecha (int d, int m, int a){
dia = d;
mes = m;
anyo = a;
}
void imprimir(){
s.o.p.(nombre + “ “);
s.o.p.(fechaNcto.dia +”/”); //ACCESO
s.o.p.(fechaNcto.mes +”/”);
s.o.p.(fechaNcto.anyo +”/”);
}
}
}
class X {
...main(...){
Persona p = new Persona();
p.imprimir(); //ERROR. ¿POR QUÉ?
}
}
Composición
(9)
 Antes de crear, se debe crear los objetos que lo
componen:


Solución 1. Crear la fecha después de la
persona
class Persona {
private String nombre;
private Fecha fechaNcto;
class X {
Persona(){
fechaNcto = new Fecha(0,0,0);
}
...
...main(...){
Persona p = new Persona();
p.setFecha(new Fecha(1,1,2000);
p.imprimir(); //CORRECTO
}
}
Solución 2. Crear la fecha a la vez que la
persona (en el constructor)
}
class X {
...main(...){
Persona p = new Persona();
p.imprimir(); //CORRECTO
}
}
… y otra
mejora más …
Polimorfismo (1)
 Es el uso de métodos de igual nombre en
distintas clases dentro de una misma jerarquía
según el objeto que se ha instanciado
A
m()
B
D
C
E
m()
F
m()
G
Polimorfismo (2)
 En concreto:
 La variable que contiene el objeto y el objeto
contenido no son del mismo tipo.
 El método que se lanza se decide en ejecución y
no en compilación.
Polimorfismo (3)
 En una familia de clases se puede definir una
referencia a la clase base y almacenar
cualquier clase derivada.
 Condiciones mínimas en Java
 Herencia
 Misma signatura del método
 Todos los métodos son potencialmente
virtuales (polimórficos).
Polimorfismo (4)
 El uso de instanceof
 Permite conocer el tipo real del objeto
que se ha instanciado.
Animal a = new PastorAleman();
System.out.println(a instanceof PastorAleman);
Polimorfismo (5)
 El polimorfismo de datos permite casting
 El casting en herencia no cambia ningún
dato, ningún tipo.
 Permite ver “como si” y acceder a sus métodos.
 Sólo funciona si es válido (jerarquía).
 Sólo puede convertirse hacia arriba en la
jerarquía.
 A menudo se hace tras un instaceof

if (a instanceof PastorAleman)
((PastorAleman)a).ladra();
… y ahora a
trabajar …
Ejercicio
 Generar la siguiente jerarquía:
ANIMAL
PERRO
FELINO
GATO
AVE
LINCE
CANARIO
PALOMA
 Animal no puede ser instanciada.
 Todas los objetos tienen un método que dice su
nombre (se guarda como atributo).
 Todas los objetos tienen un método que dicen que
sonido hacen (no se guarda como atributo).
Preguntas
 ¿Qué es toString()?
 ¿Qué es equals(Object o2)?
Wrappers (envoltorios) (1)
 Los tipos de datos primitivos pueden ser
tratados como objetos
 Se utilizan clases que sirven como
envoltorios.
 Existen clases para cada tipo
 Integer
 Double
 Char
…
Wrappers (envoltorios) (2)
 Los tipos de datos primitivos pueden ser
tratados como objetos
 Tienen constructores muy sencillos
 Integer i = new Integer(5)
 Métodos conversores
 int j = i.intValue()
Wrappers (envoltorios) (2)
 Los tipos de datos primitivos pueden ser
tratados como objetos
 Métodos conversores desde String
 double r = Double.parseDouble( “185” );
 Métodos estáticos genéricos del tipo
 Double.isNaN(5.75)
 Las últimas versiones de Java hacen las
conversiones automáticas

Integer i = 5; System.out.println( i + 3 );
… y ahora somos unos animales
de la programación.
Jerarquía de Clases: Herencia, Composición
y Polimorfismo
Programación II
Dr. Javier Nieves Acedo
Descargar

Slides