![]() ![]() ![]() ![]() |
La herencia y el polimorfismo |
Añadiendo nuevas clases a la jerarquía
figura1:
Figura.java, FiguraApp1.java
Ampliamos el árbol jerárquico de las clases que describen las figuras planas regulares, para acomodar a dos clases que describen las figuras planas, triángulo y cuadrado. La relación jerárquica se muestra en la figura.
La clase Cuadrado es una clase especializada de Rectangulo, ya que un cuadrado tiene los lados iguales. El constructor solamente precisa de tres argumentos los que corresponden a la posición de la figura y a la longitud del lado
class Cuadrado extends Rectangulo{ public Cuadrado(int x, int y, double dimension){ super(x, y, dimension, dimension); } } |
El constructor de la clase derivada llama al constructor de la clase base y le pasa la posición x e y de la figura, el ancho y alto que tienen el mismo valor. No es necesario redefinir una nueva función area. La clase Cuadrado hereda la función area definida en la clase Rectangulo.
La clase derivada Triángulo, tiene como datos, aparte de su posición (x, y) en el plano, la base y la altura del triángulo.
class Triangulo extends Figura{ protected double base, altura; public Triangulo(int x, int y, double base, double altura){ super(x, y); this.base=base; this.altura=altura; } public double area(){ return base*altura/2; } } |
El constructor de la clase Triangulo llama al constructor de la clase Figura, le pasa las coordenadas x e y de su centro, y luego inicializa los miembros dato base y altura.
En la definición de la función area, se calcula el área del triángulo como producto de la base por la altura y dividido por dos.
Veamos ahora la llamada a la función figuraMayor. Primero, creamos un array del tipo Figura, guardando en sus elementos las direcciones devueltas por new al crear cada uno de los objetos.
Figura[] fig=new Figura[4]; fig[0]=new Rectangulo(0,0, 5.0, 2.0); fig[1]=new Circulo(0,0, 3.0); fig[2]=new Cuadrado(0, 0, 5.0); fig[3]=new Triangulo(0,0, 7.0, 12.0); Figura fMayor=figuraMayor(fig); System.out.println("El área mayor es "+fMayor.area());
Pasamos el array fig a la función figuraMayor, el valor que retorna lo guardamos en fMayor. Para conocer el valor del área, desde fMayor se llamará a la función miembro area. Se llamará a la versión correcta dependiendo de la referencia al tipo de objeto que guarda fMayor.
Si fMayor guarda una referencia a un objeto de la clase Circulo, llamará a la función area definida en dicha clase. Si fMayor guarda una referencia a un objeto de la clase Triangulo, llamará a la función area definida en dicha clase, y así sucesivamente.
El operador instanceof tiene dos operandos: un objeto en el lado izquierdo y una clase en el lado derecho. Esta expresión devuelve true o false dependiendo de que el objeto situado a la izquierda sea o no una instancia de la clase situada a la derecha o de alguna de sus clases derivadas.
Por ejemplo.
Rectangulo rect=new Rectangulo(0, 0, 5.0, 2.0); rect instanceof String //false rect instanceof Rectangulo //true
El objeto rect de la clase Rectangulo no es un objeto de la clase String. El objeto rect si es un objeto de la clase Rectangulo.
Veamos la relación entre rect y las clases de la jerarquía
rect instanceof Figura //true rect instanceof Cuadrado //false
rect es un objeto de la clase base Figura pero no es un objeto de la clase derivada Cuadrado
La herencia es la propiedad que permite la creación de nuevas clases a partir de clases ya existentes. La clase derivada hereda los datos y las funciones miembro de la clase base, y puede redefinir algunas de las funciones miembro o definir otras nuevas, para ampliar la funcionalidad que ha recibido de la clase base.
Para crear un objeto de la clase derivada se llama primero al constructor de la clase base mediante la palabra reservada super. Luego, se inicializa los miembros dato de dicha clase derivada
El polimorfismo se implementa por medio de las funciones abstractas, en las clases derivadas se declara y se define una función que tiene el mismo nombre, el mismo número de parámetros y del mismo tipo que en la clase base, pero que da lugar a un comportamiento distinto, específico de los objetos de la clase derivada.
Enlace dinámico significa que la decisión sobre la función a llamar se demora hasta el tiempo de ejecución del programa.
No se pueden crear objetos de una clase abstracta pero si se pueden declarar referencias en las que guardamos el valor devuelto por new al crear objetos de las clases derivadas. Esta peculiaridad nos permite pasar un objeto de una clase derivada a una función que conoce el objeto solamente por su clase base. De este modo podemos ampliar la jerarquía de clases sin modificar el código de las funciones que manipulan los objetos de las clases de la jerarquía.