Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Ud9 POO2
Ud9 POO2
Programación
CFGS DAW
Autores:
Carlos Cacho y Raquel Torres
Revisado por:
Lionel Tarazón – [email protected]
2019/2020
Licencia
Nomenclatura
A lo largo de este tema se utilizarán distintos símbolos para distinguir elementos importantes
dentro del contenido. Estos símbolos son:
Importante
Atención
Interesante
ÍNDICE DE CONTENIDO
1. La clase ArrayList............................................................................................. 4
1.1 Introducción................................................................................................4
1.2 Declaración.................................................................................................4
1.3 Llenado.......................................................................................................4
1.4 Métodos de Acceso y Manipulación.................................................................5
1.5 Recorrido de un ArrayList..............................................................................5
1.6 Ejemplo 1...................................................................................................6
1.7 Ejemplo 2...................................................................................................7
2. Composición..................................................................................................... 9
3. Herencia......................................................................................................... 10
3.1 Introducción..............................................................................................10
3.2 Constructores de clases derivadas................................................................11
3.3 Métodos heredados y sobreescritos...............................................................11
3.4 Clases y métodos final................................................................................11
3.5 Acceso a miembros derivados......................................................................11
3.6 Ejemplo 3..................................................................................................12
4. Polimorfismo.................................................................................................. 16
4.1 Ejemplo 4..................................................................................................16
5. Clases Abstractas........................................................................................... 18
6. Interfaces...................................................................................................... 19
6.1 Ejemplo 6..................................................................................................20
7. Agradecimientos............................................................................................ 22
PROGRAMACIÓN UD09. PROGRAMACIÓN ORIENTADA A OBJETOS II
1. LA CLASE ARRAYLIST
La Clase ArrayList no está directamente relacionada con la programación orientada a objetos, pero
este es un buen momento para aprender a utilizarla.
1.1 Introducción
Un ArrayList es una estructura de datos dinámica del tipo colección que implementa una lista de
tamaño variable. Es similar a un array con las ventajas de que su tamaño crece dinámicamente
conforme se añaden elementos (no es necesario fijar su tamaño al crearlo) y permite almacenar
datos y objetos de cualquier tipo.
1.2 Declaración
Un ArrayList se declara como una clase más:
ArrayList lista = new ArrayList();
Necesitaremos importar la clase:
import java.util.ArrayList;
1.3 Llenado
Para insertar datos o elementos en un ArrayList puede utilizarse el método add().
En el siguiente ejemplo insertamos datos int, double, char y String:
lista.add(-25);
lista.add(3.14);
lista.add(‘A’);
lista.add(“Luis”);
En el siguiente ejemplo insertamos objetos de la clase Persona:
lista.add(new Persona(“28751533Q”, "María", "Maida García", 37));
lista.add(new Persona(“65971552A”, "Luis", "González Collado", 17));
lista.add(new Persona(“16834954R”, "Raquel", "Dobón Pérez", 62));
Este código añade punteros a tres objetos del tipo Persona al ArrayList. Es decir, cada posición de
la lista apuntará a un objeto Persona diferente. También se podría haber hecho lo siguiente:
Persona p = new Persona(“28751533Q”, "María", "Maida García", 37);
lista.add(p);
1.6 Ejemplo 1
Ejemplo que crea, rellena y recorre un ArrayList de dos formas diferentes. Cabe destacar que, por
defecto, el método System.out.println() invoca al método toString() de los elementos que se le
pasen como argumento, por lo que realmente no es necesario utilizar toString() dentro de println().
Salida:
1.7 Ejemplo 2
Tenemos la clase Producto con:
• Dos atributos: nombre (String) y cantidad (int).
• Un constructor con parámetros.
• Un constructor sin parámetros.
• Métodos get y set asociados a los atributos.
En el programa principal creamos una lista de productos y realizamos operaciones sobre ella:
Salida:
2. COMPOSICIÓN
Por ejemplo, un rectángulo está compuesto por dos puntos (cada uno con sus coordenadas x,y).
public class Rectangulo {
Punto p1;
Punto p2;
...
}
Una cuenta bancaria tiene un titular y un autorizado (ambas son personas con dni, nombre,
dirección, teléfono, etc.). Además de el saldo, la cuenta tendrá registrado un listado de movimientos
(cada movimiento tiene asociada un tipo, fecha, cantidad, concepto, origen o destino, etc.).
public class CuentaBancaria {
Persona titular;
Persona autorizado;
double saldo;
Movimiento movimientos[];
...
}
La composición de clases es una capacidad muy potente de la POO ya que permite diseñar
software como un conjunto de clases que colaboran entre sí: Cada clase se especializa en una tarea
concreta y esto permite dividir un problema complejo en varios sub-problemas pequeños. También
facilita la modularidad y reutilización del código.
3. HERENCIA
3.1 Introducción
La herencia es una de las capacidades más importantes y distintivas de la POO. Consiste en derivar
o extender una clase nueva a partir de otra ya existente de forma que la clase nueva hereda todos
los atributos y métodos de la clase ya existente.
A la clase ya existente se la denomina superclase, clase base o clase padre. A la nueva clase se la
denomina subclase, clase derivada o clase hija.
Cuando derivamos (o extendemos) una nueva clase, ésta hereda todos los
datos y métodos miembro de la clase existente.
Por ejemplo, si tenemos un programa que va a trabajar con alumnos y profesores, éstos van a
tener atributos comunes como el nombre, dni, dirección o teléfono. Pero cada uno de ellos tendrán
atributos específicos que no tengan los otros. Por ejemplo los alumnos tendrán el número de
expediente, el ciclo y curso que cursan y sus notas; por su parte los profesores tendrán el código de
profesor, el departamento al que pertenecen, los módulos que imparten y su horario.
Por lo tanto, en este caso lo mejor es declarar una clase Persona con los atributos comunes
(Nombre, DNI, Dirección, Teléfono) y dos sub-clases Alumno y Profesor que hereden de Persona
(además de tener sus propios atributos).
Es importante recalcar que Alumno y Profesor también heredarán todos los métodos de Persona.
3.6 Ejemplo 3
En este ejemplo vamos a crear las clase Persona y sus clases heredadas: Alumno y Profesor.
En la clase Persona crearemos el constructor, un método para mostrar los atributos y los getters y
setters. Las clases Alumno y Profesor heredarán de la clase Persona (utilizando la palabra reservada
extends) y cada una tendrá sus propios atributos, un constructor que llamará también al constructor
de la clase Persona (utilizando el método super()), un método para mostrar sus atributos, que
también llamará al método de Persona y los getters y setters.
Es interesante ver cómo se ha sobreescrito el método mostrarPersona() en las clases heredadas. El
método se llama igual y hace uso de la palabra reservada super para llamar al método de
mostrarPersona() de Persona. En la llamada del main tanto el objeto a (Alumno) como el objeto
profe (Profesor) pueden hacer uso del método mostrarPersona().
Persona
Alumno
(hereda de Persona)
Profesor
(hereda de Persona)
Programa Principal
Salida:
4. POLIMORFISMO
La sobreescritura de métodos constituye la base de uno de los conceptos más potentes de Java: la
selección dinámica de métodos, que es un mecanismo mediante el cual la llamada a un método
sobreescrito se resuelve en tiempo de ejecución y no durante la compilación. La selección dinámica
de métodos es importante porque permite implementar el polimorfismo durante el tiempo de
ejecución. Una variable de referencia a una superclase se puede referir a un objeto de una subclase.
Java se basa en esto para resolver llamadas a métodos sobreescritos en el tiempo de ejecución.
Lo que determina la versión del método que será ejecutado es el tipo de objeto al que se hace
referencia y no el tipo de variable de referencia.
El polimorfismo es fundamental en la programación orientada a objetos porque permite que una
clase general especifique métodos que serán comunes a todas las clases que se deriven de esa
misma clase. De esta manera las subclases podrán definir la implementación de alguno o de todos
esos métodos.
La superclase proporciona todos los elementos que una subclase puede usar directamente.
También define aquellos métodos que las subclases que se deriven de ella deben implementar por
sí mismas. De esta manera, combinando la herencia y la sobreescritura de métodos, una superclase
puede definir la forma general de los métodos que se usarán en todas sus subclases
4.1 Ejemplo 4
Vamos probar un ejemplo sencillo pero que resume todo lo importante del polimorfismo.
Vamos a crear la clase Madre con un método llamame(). A continuación crearemos dos clases
derivadas de ésta: Hija1 e Hija2, sobreescribiendo el método llamame(). En el main crearemos un
objeto de cada clase y los asignaremos a una variable de tipo Madre (llamada madre2) con la que
llamaremos al método llamame() de los tres objetos.
Es importante observar que la variable Madre madre2 se puede asignar a objetos de clase Hija1 e
Hija2. Esto es posible porque Hija1 e Hija2 también son de tipo Madre (debido a la herencia).
También es importante ver que la variable Madre madre2 llamará al método llamame() de la clase
del objeto al que hace referencia (debido al polimorfismo).
Obsérvese las llamadas madre2.llamame() de las líneas 36 en adelante:
• En el primero se invoca al método llamame() de la clase Madre porque ‘madre2’ hace
referencia a un objeto de la clase Madre.
• En el segundo se invoca al método llamame() de la clase Hija1 porque ahora ‘madre2’ hace
referencia a un objeto de la clase Hija1.
• En el tercero se invoca al método llamame() de la clase Hija2 porque ahora ‘madre2’ hace
referencia a un objeto de la clase Hija2.
Salida:
5. CLASES ABSTRACTAS
Una clase abstracta es una clase que declara la existencia de algunos métodos pero no su
implementación (es decir, contiene la cabecera del método pero no su código). Los métodos sin
implementar son métodos abstractos.
Una clase abstracta puede contener tanto métodos abstractos (sin implementar) como no
abstractos (implementados). Pero al menos uno debe ser abstracto.
Para declarar una clase o método como abstracto se utiliza el modificador abstract.
Una clase abstracta no se puede instanciar, pero sí heredar. Las subclases
tendrán que implementar obligatoriamente el código de los métodos abstractos (a
no ser que también se declaren como abstractas).
Las clases abstractas son útiles cuando necesitemos definir una forma generalizada de clase que
será compartida por las subclases, dejando parte del código en la clase abstracta (métodos
“normales”) y delegando otra parte en las subclases (métodos abstractos).
No pueden declararse constructores o métodos estáticos abstractos.
La finalidad principal de una clase abstracta es crear una clase heredada a partir de ella. Por ello,
en la práctica es obligatorio aplicar herencia (si no, la clase abstracta no sirve para nda). El caso
contrario es una clase final, que no puede heredarse como ya hemos visto. Por lo tanto una clase no
puede ser abstract y final al mismo tiempo.
Por ejemplo, esta clase abstracta Principal tienes dos métodos: uno concreto y otro abstracto.
public abstract class Principal {
// Método concreto con implementación
public void metodoConcreto() {
...
}
// Método abstracto sin implementación
public abstract void metodoAbstracto();
}
Esta subclase hereda de Principal ambos métodos, pero está obligada a implementar el código del
método abstracto.
class Secundaria extends Principal {
// Implementación concreta
public void metodoAbstracto() {
...
}
}
6. INTERFACES
Una interfaz es una declaración de atributos y métodos sin implementación (sin definir el código
de los métodos). Se utilizan para definir el conjunto mínimo de atributos y métodos de las clases
que implementen dicha interfaz. En cierto modo, es parecido a una clase abstracta con todos sus
miembros abstractos.
Si una clase es una plantilla para crear objetos, una interfaz es una pantilla para crear clases.
Un interfaz es una declaración de atributos y métodos sin implementación.
Mediante la construcción de un interfaz, el programador pretende especificar qué caracteriza a
una colección de objetos e, igualmente, especificar qué comportamiento deben reunir los objetos
que quieran entrar dentro de sea categoría o colección.
En una interfaz también se pueden declarar constantes que definen el comportamiento que deben
soportar los objetos que quieran implementar esa interfaz.
La sintaxis típica de una interfaz es la siguiente:
public interface Nombre {
// Declaración de atributos y métodos (sin definir código)
}
Si una interfaz define un tipo pero ese tipo no provee de ningún método, podemos preguntarnos:
¿para qué sirven entonces las interfaces en Java?
La implementación (herencia) de una interfaz no podemos decir que evite la duplicidad de código
o que favorezca la reutilización de código puesto que realmente no proveen código.
En cambio sí podemos decir que reúne las otras dos ventajas de la herencia: favorecer el
mantenimiento y la extensión de las aplicaciones. ¿Por qué? Porque al definir interfaces
permitimos la existencia de variables polimórficas y la invocación polimórfica de métodos.
Un aspecto fundamental de las interfaces en Java es separar la especificación de una clase (qué
hace) de la implementación (cómo lo hace). Esto se ha comprobado que da lugar a programas más
robustos y con menos errores.
Es importante tener en cuenta que:
• Una interfaz no se puede instanciar en objetos, solo sirve para implementar clases.
• Una clase puede implementar varias interfaces (separadas por comas).
• Una clase que implementa una interfaz debe de proporcionar implementación para todos y
cada uno de los métodos definidos en la interfaz.
• Las clases que implementan una interfaz que tiene definidas constantes pueden usarlas en
cualquier parte del código de la clase, simplemente indicando su nombre.
6.1 Ejemplo 6
En este ejemplo vamos a crear una interfaz Figura y posteriormente implementarla en varias
clases. Para crear una interfaz debemos pinchar con el botón derecho sobre el paquete donde la
queramos crear y despues NEW > Java Interface.
Vamos a ver un ejemplo simple de definición y uso de interfaz en Java. Las clases que vamos a usar
y sus relaciones se muestran en el esquema:
En este ejemplo la interface Figura define un tipo de dato. Por ello podemos crear un ArrayList de
figuras donde insertamos cuadrados, círculos, rectángulos, etc. (polimorfismo). Esto nos permite
darle un tratamiento común a todas las figuras: Mediante un bucle while recorremos la lista de
figuras y llamamos al método area() que será distinto para cada clase de figura.
7. AGRADECIMIENTOS