Clases
abstractas
Concepto
Hay ocasiones,
cuando se desarrolla una jerarquía de clases en que algún comportamiento está
presente en todas ellas pero se materializa de forma distinta para cada una. Por
ejemplo, pensemos en una estructura de clases para manipular figuras
geométricas. Podríamos pensar en tener una clase genérica, que podría llamarse
FiguraGeometrica y una serie de clases que extienden a la anterior que podrían
ser Circulo, Poligono, etc. Podría haber un método dibujar dado que sobre todas
las figuras puede llevarse a cabo esta acción, pero las operaciones concretas
para llevarla a cabo dependen del tipo de figura en concreto (de su clase). Por
otra parte la acción dibujar no tiene sentido para la clase genérica
FiguraGeometrica, porque esta clase representa una abstracción del conjunto de
figuras posibles.
Para resolver
esta problemática Java proporciona las clases y métodos abstractos. Un método
abstracto es un método declarado en una clase para el cual esa clase no
proporciona la implementación (el código). Una clase abstracta es una clase que
tiene al menos un método abstracto. Una clase que extiende a una clase abstracta
debe implementar los métodos abstractos (escribir el código) o bien volverlos a
declarar como abstractos, con lo que ella misma se convierte también en clase
abstracta.
Declaración e implementación de métodos abstractos
Siguiendo con el
ejemplo del apartado anterior, se puede escribir:
abstract
class FiguraGeometrica {
abstract
void dibujar();
}
class Circulo extends FiguraGeometrica {
class Circulo extends FiguraGeometrica {
void dibujar()
{
// codigo para
dibujar Circulo
}
}
}
La clase
abstracta se declara simplemente con el modificador abstract en su
declaración. Los métodos abstractos se declaran también con el mismo
modificador, declarando el método pero sin implementarlo (sin el bloque de
código encerrado entre {}). La clase derivada se declara e implementa de forma
normal, como cualquier otra. Sin embargo si no declara e implementa los métodos
abstractos de la clase base (en el ejemplo el método dibujar) el compilador
genera un error indicando que no se han implementado todos los métodos
abstractos y que, o bien, se implementan, o bien se declara la clase abstracta.
Referencias y objetos abstractos
Se pueden crear
referencias a clases abstractas como cualquier otra. No hay ningún problema en
poner:
FiguraGeometrica
figura;
Sin embargo una
clase abstracta no se puede instanciar, es decir, no se pueden crear objetos de
una clase abstracta. El compilador producirá un error si se
intenta:
FiguraGeometrica
figura = new FiguraGeometrica();
Esto es
coherente dado que una clase abstracta no tiene completa su implementación y
encaja bien con la idea de que algo abstracto no puede materializarse.
Sin embargo
utilizando el up-casting visto en el capítulo dedicado a la Herencia si se puede
escribir:
FiguraGeometrica
figura = new Circulo(. . .);
figura.dibujar();
La invocación al
método dibujarse resolverá en tiempo de ejecución y la JVM llamará al método de
la clase adecuada. En nuestro ejemplo se llamará al método dibujarde la clase
Circulo
Código Fuente Musica2.java
import java.util.*;
abstract class Instrumento {
public abstract void tocar();
public String tipo() {
return "Instrumento";
}
public abstract void afinar();
}
class Guitarra extends Instrumento {
public void tocar() {
System.out.println("Guitarra.tocar()");
}
public String tipo() { return "Guitarra"; }
public void afinar() {}
}
class Piano extends Instrumento {
public void tocar() {
System.out.println("Piano.tocar()");
}
public String tipo() { return "Piano"; }
public void afinar() {}
}
class Saxofon extends Instrumento {
public void tocar() {
System.out.println("Saxofon.tocar()");
}
public String tipo() { return "Saxofon"; }
public void afinar() {} }
// Un tipo de Guitarra
class Guzla extends Guitarra {
public void tocar() {
System.out.println("Guzla.tocar()");
}
public void afinar() {
System.out.println("Guzla.afinar()");
} }
// Un tipo de Guitarra
class Ukelele extends Guitarra {
public void tocar() { System.out.println("Ukelele.tocar()");
}
public String tipo() { return "Ukelele"; }
}
public class Musica2 {
// No importa el tipo de Instrumento,
// seguirá funcionando debido a Polimorfismo:
static void afinar(Instrumento i) { // ... i.tocar();
}
static void afinarTodo(Instrumento[] e) {
for(int i = 0; i < e.length; i++) afinar(e[i]);
}
public static void main(String[] args) {
// Declarar un Arreglo SIN INSTANCIAS es valido en Clases Abstractas Instrumento[] orquesta = new Instrumento[5];
// Generar una INSTANCIA de una la Clase Abstracta no es valido
// Instrumento nuevo = new Instrumento();
int i = 0;
// Up-casting al asignarse el Arreglo
orquesta[i++] = new Guitarra();
orquesta[i++] = new Piano();
orquesta[i++] = new Saxofon(); orquesta[i++] = new Guzla();
orquesta[i++] = new Ukelele(); afinarTodo(orquesta);
}
}
|
La
Clase anterior es idéntica aquella definida en el ejemplo de Polimorfismo, sin
embargo, la Clase Base de
Instrumento
fue definida como abstract, algunos detalles de esta definición :
· Nótese
que los métodos definidos como abstract no contienen ningún tipo de
código dentro de ellos, inclusive no declaran ni llaves (
{
}
).
· Cuando
es definido más de un método como abstract, es necesario que la Clase
como tal sea definida también como abstract.
La
característica de hacer una Clase/Método abstract reside en que no puede ser
generada una instancia de la misma, este comportamiento se demuestra en el
método principal (main)
· Aunque
dentro del método sea generado un Arreglo de esta Clase abstracta, recuerde que
un arreglo es únicamente un contenedor de Objetos, esto permite que sea generado
sin ningún error.
· Dentro
de comentarios se encuentra la generación de una instancia del tipo
Instrumento la cual generaría un error al ser compilada la Clase.
No hay comentarios:
Publicar un comentario