Programación UT7 - Utilización Avanzada de Clases-V2
Programación UT7 - Utilización Avanzada de Clases-V2
clases
Composición, herencia, clases abstractas, interfaces
y polimorfismo
Relaciones entre
clases
Relaciones entre clases (I)
● La clase se describe como un mecanismo de definición para
construir objetos.
● Es vital establecer relaciones entre clases al diseñar
conjuntos de clases para automatizar el tratamiento de la
información.
Relaciones entre clases (II)
Tipos de relaciones entre clases
● Un coche es un vehículo.
● Un empleado es una persona.
● Un rectángulo es una figura geométrica en el plano.
● Un cocodrilo es un reptil.
● Una ventana en una aplicación gráfica puede heredar de
JFrame.
● Una caja de diálogo puede ser un tipo de JDialog.
herencia (iii)
Expresión Idiomática para Identificar Herencia:
class <nombreClase> {
[modificadores] <NombreClase1> nombreAtributo1;
[modificadores] <NombreClase2> nombreAtributo2;
}
sintaxis de la composición (y II)
● Ejemplo: declaramos una clase Rectangulo que contiene
puntos en el plano
● La clase Rectangulo tiene una relación de composición con
la clase Punto, pues un rectángulo está compuesto de 2
puntos en el plano para definirlo
class Rectangulo {
private Punto vertice1;
private Punto vertice2;
}
usos de la composición (I)
● Cuando se escriben clases que contienen objetos de otras
clases hay que tener precaución con aquellos métodos que
devuelvan información acerca de los atributos/campos de
la clase (métodos get)
● Cuando hablamos de las propiedades con los métodos get y
set vimos que a través de estos métodos se controlaba el
acceso a los atributos/campos de la clase y su
actualización
● Hasta ahora solamente hemos tratado con tipos básicos a
la hora de definir atributos/campos
usos de la composición (II)
● Al devolver un tipo básico (tipo por valor) en un método
get se devuelve automáticamente una copia del dato, por
lo que el valor original dentro de la clase permanece sin
alterar independientemente de lo que haga el código que
llama al método get
● Cuando se devuelve un objeto (tipo por referencia) en un
método get se está devolviendo una referencia al dato
original dentro de la clase, por lo cual se podría
modificar directamente desde código fuera de la clase sin
pasar por el método set
usos de la composición (III)
● Para evitar ese tipo de situaciones lo anterior hay
diversas alternativas para evitar la devolución directa
de un atributo que sea un objeto:
○ Devolver siempre tipos primitivos.
○ Crear un nuevo objeto que sea una copia del atributo que quieres
devolver y utilizar ese objeto como valor de retorno. Es decir, crear
una copia del objeto especialmente para devolverlo.
● Es posible que en algunos casos sí se necesite realmente
la referencia al atributo original (algo muy habitual en
el caso de atributos estáticos).
usos de la composición (IV)
public Punto obtenerVertice1 () // Creación de un nuevo punto extrayendo sus
atributos
{
double x, y;
Punto p;
x= this.vertice1.obtenerX();
y= this.vertice1.obtenerY();
p= new Punto (x,y);
return p;
}
usos de la composición (V)
public Punto obtenerVertice1 () // Utilizando el constructor copia de Punto (si es que
está definido)
{
Punto p;
p = new Punto (this.vertice1); // Uso del constructor copia
return p;
}
usos de la composición (VI) - constructores
● A la hora de escribir clases que contengan como atributos
objetos de otras clases hay que tener en cuenta que el
constructor de la clase contenedora debe invocar a los
constructores de las clases de los objetos contenidos.
● Al pasar un objeto (tipo de dato por referencia) que se
pasan como parámetros para rellenar el contenido de los
atributos es conveniente hacer una copia de esos objetos
y utilizar esas copias
● Si no, sería posible que el código que llama al
constructor tuviera acceso a un objeto que sea un campo
privado de la clase al guardar la referencia
usos de la composición (VII) - Constructores
● Si además el objeto parámetro que se pasa al constructor
formaba parte de otro objeto y esos objetos son
modificados en el futuro desde otra parte del código
ajeno a la clase se pueden producir efectos colaterales
inesperados
● Los objetos al ser tipos de datos por referencia
realmente apunta a la zona de memoria en la que se
encuentra el objeto. Por eso, puedes tener un único
objeto y múltiples referencias a él, pero modificar un
objeto desde cualquier referencia lo modifica para todas
usos de la composición (VIII) - Métodos set
● Sólo se crean objetos cuando se llama a un constructor
(usando new XXX). Al realizar asignaciones o pasos de
parámetros no se están copiando o pasando copias de los
objetos, sino solamente las referencias al mismo objeto
● Si en un método set que reciba un objeto no hacemos una
copia del mismo para almacenarlo como un objeto nuevo,
nuestra clase estaría ofreciendo una referencia al objeto
interno que posee a un código externo permitiendo
modificarlo
usos de la composición (IX)
public Rectangulo (Punto vertice1, Punto vertice2)
{
this.vertice1= new Punto (vertice1.obtenerX(), vertice1.obtenerY() );
this.vertice2= new Punto (vertice2.obtenerX(), vertice2.obtenerY() );
}
public Rectangulo (Punto vertice1, Punto vertice2)
{
this.vertice1= new Punto (vertice1 );
this.vertice2= new Punto (vertice2 );
}
}
}
Clases anidadas (II)
Tipos de clases internas:
● Clases internas estáticas declaradas con el modificador
static.
● Clases internas miembro, conocidas habitualmente como
clases internas.
● Clases internas locales, que se declaran en el interior
de un bloque de código (normalmente dentro de un método).
● Clases anónimas, similares a las internas locales, pero
sin nombre (sólo existirá un objeto de ellas y, al no
tener nombre, no tendrán constructores). Se suelen usar
en la gestión de eventos en los interfaces gráficos.
Clases anidadas (y III)
● Las clases anidadasnpueden ser declaradas con los
modificadores public, protected, private o de paquete,
como el resto de miembros.
● Las clases internas (no estáticas) tienen acceso a otros
miembros de la clase dentro de la que está definida
aunque sean privados
● Las clases internas estáticas solamente tienen acceso a
miembros estáticos también de la clase que las contiene
Herencia
Conceptos de la herencia de clases (I)
● La herencia es el mecanismo que permite definir una nueva
clase a partir de otra, pudiendo añadir nuevas
características, sin tener que volver a escribir todo el
código de la clase base.
● La clase de la que se hereda se llama clase base, clase
padre o superclase. A la clase que hereda se le suele
llamar clase hija, clase derivada o subclase.
Conceptos de la herencia de clases (II)
Conceptos de la herencia de clases (III)
● Una clase derivada puede ser a su vez clase padre de otra que
herede de ella y así sucesivamente dando lugar a una jerarquía
de clases
● Una clase hija no tiene acceso a los miembros privados de su
clase padre, tan solo a los públicos (como cualquier parte del
código tendría) y los protegidos (a los que sólo tienen acceso
las clases derivadas y las del mismo paquete).
● Aquellos miembros que sean privados en la clase base también
habrán sido heredados, pero el acceso a ellos estará
restringido al propio funcionamiento de la superclase y sólo
se podrá acceder a ellos si la superclase ha dejado algún
medio indirecto para hacerlo (por ejemplo a través de algún
método).
Conceptos de la herencia de clases (IV)
● Todos los miembros de la superclase son heredados por la
subclase. Algunos de estos miembros heredados podrán ser
redefinidos o sobrescritos (overriden) y también podrán
añadirse nuevos miembros.
● Se podría decir que se está “ampliando” la clase base con
características adicionales o modificando algunas de
ellas (proceso de especialización).
● Una clase derivada extiende la funcionalidad de la clase
base sin tener que volver a escribir su códigoya que
hereda todas las propiedades y métodos de la clase padre
Sintaxis de la herencia (I)
● En Java la herencia se indica mediante la palabra
reservada extends
}
Sintaxis de la herencia (III)
Un objeto de la clase Alumno contendrá los atributos grupo y
notaMedia (propios de la clase Alumno) y también nombre,
apellidos y fechaNacim heredados de la clase Persona
}
Acceso a miembros heredados (I)
● No es posible acceder a miembros privados de una
superclase.
● Para poder acceder a ellos se pueden hacer públicos pero
entonces se daría acceso a cualquier clase y puede no
desearse.
● Para ello existe el modificador protected (protegido) que
permite el acceso desde clases heredadas, pero no desde
otras clases fuera de la jerarquía
Acceso a miembros heredados (II)
What is the difference between public, protected,
package-private and private in Java?
Acceso a miembros heredados (III)
● Ejemplo: al definir los atributos de la clase Persona
como private la clase Alumno que hereda de Persona no
tiene acceso a los mismos
@Override
public void mostrar () {
super.mostrar (); // Llamada al método “mostrar” de la superclase
}
}
Constructores y herencia (I)
● Ya hemos visto en la UT5 que en una clase, un constructor
puede llamar a otro constructor de la misma clase
utilizando la referencia this.
● La llamada a this solo puede hacerse en la primera línea
del constructor.
● Un constructor de una clase derivada puede llamar al
constructor de su clase base utilizando la palabra clave
super. Esto permite inicializar los atributos heredados
antes de los específicos de la clase derivada.
Constructores y herencia (II)
● Si no se incluye una llamada explícita a super() dentro
del constructor de la clase derivada, el compilador la
añade automáticamente.
● Esto resulta en una llamada en cadena de constructores de
la superclase hasta llegar a la clase Object en la
jerarquía de Java.
● El constructor por defecto, creado por el compilador si
no se ha escrito ninguno incluye una llamada a super()
como primera acción. Esta llamada asegura que los
constructores de las superclases se ejecuten
correctamente antes de la inicialización de los atributos
de la clase derivada.
Constructores y herencia (y III)
Ejemplo
public class Persona {
public Persona (String nombre, String apellidos, LocalDate fechaNacim) {
this.nombe= nombre;
this.apellidos= apellidos;
this.fechaNacim= LocalDate.of(fechaNacim.getYear(), fechaNacim.getMonthValue(),
fechaNacim.getDayOfMonth());
}
}
public class Alumno {
public Alumno (String nombre, String apellidos, LocalDate fechaNacim, String grupo,
double notaMedia) {
super (nombre, apellidos, fechaNacim);
this.grupo= grupo;
this.notaMedia= notaMedia;
}
}
La clase Object en Java (I)
Todas las clases en Java son descendentes de la clase
Object.
Esta clase define los estados y comportamientos básicos que
deben tener todos los objetos.
Entre estos comportamientos, se encuentran:
● La posibilidad de compararse.
● La capacidad de convertirse a cadenas.
● La habilidad de devolver la clase del objeto.
La clase Object en Java (y II)
Entre los métodos que incorpora la clase Object y que por
tanto hereda cualquier clase en Java están:
Herencia múltiple
● La herencia múltiple permite heredar los miembros de
múltiples clases para formar una nueva clase derivada
● La herencia múltiple puede causar ambigüedades cuando hay
miembros con el mismo identificador en clases base
diferentes.¿Qué miembro se hereda en caso de ambigüedad?
● La herencia múltiple no está disponible en Java debido a
la complejidad y los problemas de diseño que puede causar
● En su lugar, se fomenta el uso de interfaces para lograr
la funcionalidad similar a la herencia múltiple en Java
clases abstractas
Concepto de clase Abstracta (I)
● Las clases abstractas representan conceptos demasiado
abstractos para tener instancias concretas.
● Sirven como marco o modelo para clases derivadas dentro
de una jerarquía de herencia.
● Su utilidad es proporcionar líneas generales de cómo es
una clase sin implementar todos sus métodos.
● Son útiles cuando las clases derivadas deben proporcionar
los mismos métodos pero con implementaciones específicas.
Concepto de clase Abstracta (II)
Ejemplos:
● En entornos de manipulación de objetos gráficos (donde
objetos como líneas, círculos, y rectángulos comparten
atributos y métodos comunes) una clase abstracta "objeto
gráfico" puede definir atributos comunes y algunos
métodos genéricos, dejando otros métodos sin implementar.
● En un centro educativo que utilice las clases de ejemplo
Alumno y Profesor, ambas subclases de Persona. La clase
Persona es útil como clase base para construir otras
clases que hereden de ella, pero no como una clase
instanciable de la cual vayan a existir objetos
Concepto de clase Abstracta (y III)
Declaración de una clase abstracta (I)
● Una clase abstracta es una clase que no se puede
instanciar, es decir, que no se pueden crear objetos a
partir de ella.
● La idea es permitir que otras clases deriven de ella,
proporcionando un modelo genérico y algunos métodos de
utilidad general.
● Las clases abstractas se declaran mediante el modificador
abstract
[modificador_acceso] abstract class nombreClase [herencia] [interfaces] {
}
Declaración de una clase abstracta (II)
● Una clase puede contener en su interior métodos
declarados como abstract. Para estos métodos sólo se
indica la cabecera pero no se proporciona su
implementación.
● En el caso anterior la clase tendrá que ser forzosamente
también abstract y los métodos tendrán que ser
posteriormente implementados en sus clases derivadas.
● Una clase abstracta puede contener métodos totalmente
implementados (no abstractos), los cuales se heredan en
las subclases y pueden utilizarse con normalidad
Declaración de una clase abstracta (y III)
Trabajando con clases abstractas hay que tener en cuenta:
// Zona donde se utiliza el método m sin saber realmente qué subclase se está
utilizando. (Sólo se sabrá durante la ejecución del programa)
@Override
public String devolverContenidoString() {
return String.format("Nombre:%s, apellidos:%s", nombre, apellidos);
}
}
Interfaces y polimorfismo (V)
public class Alumno extends Persona {
String grupo;
double notaMedia;
@Override
public String devolverContenidoString() {
return String.format("%s,grupo:%s, notaMedia:%f", super.devolverContenidoString(),
grupo, notaMedia);
}
}
Interfaces y polimorfismo (VI)
public class Profesor extends Persona {
@Override
public String devolverContenidoString() {
return String.format("%s,especialidad:%s, salario:%f", super.devolverContenidoString(),
especialidad, salario);
}
}
Interfaces y polimorfismo (y VII)
public static void main(String[] args) {
}
Conversión de objetos (I)
● No se puede acceder a los miembros específicos de una subclase
a través de una referencia a una superclase
● Si quieres tener acceso a todos los métodos y atributos
específicos del objeto subclase tendrás que realizar una
conversión explícita (casting) que convierta la referencia de
la superclase a la del objeto de subclase.
● Para realizar conversiones entre distintas clases es
obligatorio que exista una relación de herencia entre ellas
● Se realizará una conversión implícita o automática de subclase
a superclase siempre que sea necesario, pues un objeto de tipo
subclase siempre contendrá toda la información necesaria para
ser considerado un objeto de la superclase.
Conversión de objetos (II)
● La conversión en sentido contrario (de superclase a
subclase) debe hacerse de forma explícita y según el caso
podría dar lugar a errores por falta de información
(atributos) o de métodos. En tales casos se produce una
excepción de tipo ClassCastException.
class ClaseA {
public int atrib1;
}
class ClaseB extends ClaseA {
public int atrib2;
}
Conversión de objetos (III)
ClaseA obj; // Referencia a objetos de la ClaseA
obj= new ClaseB ();
// Referencia a objeto ClaseA, pero apunta realmente a objeto ClaseB (polimorfismo)
// Casting del tipo ClaseA al tipo ClaseB (puede dar problemas porque el objeto es
realmente del tipo ClaseA):
// Funciona (ClaseA tiene atrib1)
System.out.printf ("obj.atrib2=%d\n", ((ClaseB) obj).atrib1);