| Creación de un Televisor estándar |
| Paso 10: Clases abstractas |
Imaginemos que en nuestra casa tenemos dos mascotas. Una es un perro y la otra un gato
- cuando acariciamos
- a nuestro perro, éste baja las orejas como respuesta a nuestra acción
- a nuestro gato, éste reacciona levantando su cola
- cuando los alimentamos les damos de comer una cantidad de algún alimento apropiado para ellos,
- y la respuesta de las dos mascotas es que se acercan al recipiente donde tienen la comida y se la comen
- como podemos observar, parece predecible que la respuesta habitual de todas las mascotas cuando se les da de comer es que se acerquen al plato y se coman el contenido de éste,
- pero no podemos decir lo mismo de la respuesta que nos pueden dar todas las mascotas cuando las acariciamos
- si alguien nos preguntara cómo reacciona una mascota cuando la acarician
- nosotros responderíamos que depende. ¿Y de que depende?. Pues depende de la mascota en concreto que nos estemos refiriendo
- es decir si hablamos más concretamente de un perro diremos que éste baja las orejas y si hablamos más concretamente de un gato, diremos que levanta la cola
- pero si no nos preguntan de que mascota en concreto estamos hablando nuestra respuesta será abstracta
- es decir, no tenemos una respuesta general que sea válida para la mayoría de las mascotas
Si extrapolamos este planteamiento al mundo de los Objetos, podemos decir que tenemos
- una Superclase llamada Mascota con dos métodos
- un método acariciar() que es abstracto (abstract)
- y otro método alimentar(...) que no es abstracto
- y dos Subclases llamadas Perro y Gato
Este es el Diagrama de Clases de Diseño de nuestras mascotas
- Mascota
- es una Superclase abstracta (abstract)
- es abstracta por que contiene un método llamado acariciar() que es abstracto
- una Clase abstracta no puede ser instanciada
- en UML se sabe que una Clase es abstracta por que el nombre de la Clase está en cursiva
- -nombre: String
- Nota: Convención sobre los métodos de acceso getters y setters Apéndice - métodos de acceso getters y setters
- así pues siguiendo la convención, los métodos +setNombre(nombre: String): void y +getNombre(): String no están en la Clase de diseño Mascota
- -fechaNacimiento: Date
- Date es una Clase Java que como su nombre indica, representa una fecha
- +acariciar():void
- como este método está escrito en cursiva, esto significa que abstract
Para pasar este Diagrama de Clases de Diseño a código Java, vamos a crear un proyecto llamado promascota y un paquete llamado paqmascota
Y también vamos a crear las Clases Mascota, Perro, Gato y Aplicacion
- las Clases Mascota, Perro y Gato tal y como creaste la Clase Televisor
- y la Clase Aplicacion tal y como creaste la Clase HolaMundo en el apartado Crear una nueva Clase
Este es el código correspondiente a la Clase Mascota
|
package paqmascota;
import java.util.Date;
public abstract class Mascota {
private String nombre;
private Date fechaNacimiento;
public abstract void acariciar();
public void alimentar(String nombreAlimento){
System.out.println("Mascota - alimentar(...): me acerco al " +
nombreAlimento + ", y me lo como");
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public String getNombre(){
return nombre;
}
public void setFechaNacimiento(Date fechaNacimiento) {
this.fechaNacimiento = fechaNacimiento;
}
public Date getFechaNacimiento(){
return fechaNacimiento;
}
} |
- import java.util.Date;
- ya veremos más adelante los diferentes paquetes que contienen las múltiples librerias estándar Java
- de momento saber que hay una Clase que se llama Date que está incluida en el paquete java.util
- para que el entorno de ejecución Java sepa donde encontrar esta Clase, nosotros se lo tenemos que indicar con la palabra clave import
- public abstract class Mascota {
- en Java se sabe que una Clase es abstracta porque se utiliza la plabra reservada abstract en la declaración de la Clase
- Date fechaNacimiento;
- a menudo los entornos de desarrollo cuando nos generan código automáticament a través de sus Asistentes nos escriben la signatura completa de la Clase, es decir el nombre de la Clase y al paquete al cual pertenece. De esta forma la declaración de esta Clase se vería así: java.util.Date fechaNacimiento y no incluiría la palabra clave import
- public abstract void acariciar();
- como este método es abstracto y por lo tanto no está implementado, no tiene la llaves {} de abrir y cerrar típica de todos los métodos
- public void setNombre(String nombre) {
- en Java además de las variables de instancia que están visibles desde cualquier punto de la Clase,
- también existen las variables locales que sólo tienen visibilidad dentro de su ámbito
- es decir, sólo se puede llegar a ellas si se está dentro del mismo bloque
- un bloque se delimita por los corchetes {}, cómo pueden ser los corchetes de la definición de un método
- a la variable nombre que se encuentra en la declaración del método setNombre(String nombre) también se le considera una variable local a pesar de que no está entre dos corchetes {}
- this.nombre = nombre;
Compilamos la Clase Mascota.
Este es el código correspondiente a la Clase Perro
package paqmascota;
public class Perro extends Mascota {
public void acariciar() {
System.out.println("Perro - acariciar(): agacho las orejas");
}
}
|
- System.out.println("Perro - acariciar(): agacho las orejas");
- como ahora nos estamos refiriendo a una mascota concreta, ésta enviará el mensaje de que está agachando las orejas
Compilamos la Clase Perro.
Este es el código correspondiente a la Clase Gato
package paqmascota;
public class Gato extends Mascota {
public void acariciar() {
System.out.println("Gato - acariciar(): levanto la cola");
}
}
|
Compilamos la Clase Gato.
Ahora le toca el turno a la Clase Aplicacion que tienen que tener un método main(...) para que este programa pueda ser ejecutado.
Si añadimos el siguinete código de la Clase Aplicacion que pertenece al paquete paqmascota
package paqmascota;
public class Aplicacion {
public static void main(String[] args) {
Mascota m1 = new Mascota();
}
} |
nos aparece el siguiente error
- paqmascota.Mascota is abstract; cannot be instantiated

Ahora le añadimos el siguiente código a la Clase Aplicacion
package paqmascota;
public class Aplicacion {
public static void main(String[] args) {
// Mascota m1 = new Mascota();
Perro p1 = new Perro();
p1.alimentar("Dog Chow");
p1.acariciar();
Gato g1 = new Gato();
g1.alimentar("Cat Chow");
g1.acariciar();
}
}
|
- Perro p1 = new Perro();
- creamos una instancia de la Clase Perro que engloba a la Clase Mascota y a la Clase Perro en una sola instancia que es referenciada a través de la variable de referencia p1
- p1.alimentar("Dog Chow");
- fijémonos que en la salida provocada como respuesta a la invoación de este método
- quien está respondiendo es la Mascota acercándose al Dog Chow
- p1.acariciar();
- fijémonos que en la salida provocada como respuesta a la invoación de este método
- quien está respondiendo es el Perro agachando las orejas
- Gato g1 = new Gato();
- creamos una instancia de la Clase Gato que engloba a la Clase Mascota y a la Clase Gato en una sola instancia que es referenciada a través de la variable de referencia g1
- g1.alimentar("Cat Chow");
- fijémonos que en la salida provocada como respuesta a la invoación de este método
- quien está respondiendo es la Mascota acercándose al Cat Chow
- g1.acariciar();
- fijémonos que en la salida provocada como respuesta a la invoación de este método
- quien está respondiendo es el Gato levantando la cola
Y esta es la salida