You are on page 1of 15

Autor: Lic.

Martín Vargas
Mendoza – Argentina
Feb. 2019

Conceptos:
 Clase y Funciones Finales
 Clases Abstractas
 Interfaces
 Diferencias entre Interfaces y Clases Abstractas
Clases finales
Se puede declarar una clase como final, cuando no nos interesa crear clases
derivadas de dicha clase. La clase Cuadrado se puede declarar como final, ya que
no se espera que ningún programador necesite crear clases derivadas de
Cuadrado.

final class Cuadrado extends Rectangulo {


public Cuadrado(int x, int y, double dimension){
super(x, y, dimension, dimension);
}
}

Uno de los mecanismos que tienen los hackers para dañar o para obtener
información privada en los sistemas es la de crear una clase derivada y sustituir
dicha clase por la original. La clase derivada actúa exactamente igual que la original
pero también puede hacer otras cosas, normalmente dañinas. Para prevenir los
posibles daños, se declara la clase como final, impidiendo a cualquier programador
la creación de clases derivadas de ésta.

Por ejemplo, la clase String que es una de las más importantes en la programación
en lenguaje Java, está declarada como final. El lenguaje Java garatiza que siempre
que se utilice un string, es un objeto de la clase String que se encuentra en el
paquete java.lang.String, y no cualquier otro string.
Métodos finales
Como se ha comentado al introducir la herencia, una de las formas de aprovechar el código
existente, es la de crear una clase derivada y redefinir algunos de los métodos de la clase
base.

class Base {
final public void funcionFinal(){
// Se escribe lo necesario
}
public void dibujar(Graphics g){
}
}
class Derivada extends Base {
public void dibujar(Graphics g){
//dibujar algunas figuras
}
}
La clase Base define una función miembro pública dibujar, que no dibuja nada en el
contexto gráfico g. La clase Derivada redefine la función miembro dibujar, para dibujar
algunas figuras en el contexto grafico g. La función que se redefine tiene que tener la misma
declaración en la clase Base y en la clase Derivada.

Para evitar que las clase derivadas redefinan una función miembro de una clase base, se le
antepone la palabra clave final. La función miembro funcionFinal de la clase Base no se
puede redefinir en la clase Derivada, pero si se puede redefinir la función miembro dibujar.
Clases Abstractas
La idea de una clase abstracta es que hay que heredar necesariamente; en otro
caso no pueden ser utilizadas, justamente lo contrario de la de una clase final.

Definición: Una clase es abstracta cuando tiene algún método (o métodos) sin
definir. Por tanto no es posible declarar objetos de una clase abstracta. Serán las
clases derivadas las que completen esos métodos y de las que podremos definir
objetos.

Una clase abstracta sirve de base para otras clases, pero ella misma no puede ser
instanciada (declarar objetos de su tipo). Esto se hace porque la implementación
de alguno de los métodos depende de cada caso concreto y no se puede hacer en
general.
Clases Abstractas
PolígonoRegular.java
public abstract class PoligonoRegular {
La palabra clase abstract indica que
protected int numLados; la clase contiene métodos
protected double lado; // longitud de un lado abstractos, es decir métodos aún
public PoligonoRegular(int numLados, double lado) { no definidos. La clase está por
this.numLados = numLados; tanto, incompleta, y no podemos
this.lado = lado; declarar objetos de tipo
} PolígonoRegular:

public double perimetro() {


return numLados*lado; Observación: Las clases finales lo
}
son por decisión del programador,
// este método lo tiene que hacer cada clase derivada;
// depende de cada polígono regular pero las abstractas lo son porque el
public abstract double area(); programador no es capaz de
} implementar alguno de los
Principal.java métodos, pero aún así cree que
public class Principal { debe existir.
public static void main(String[] args) {
PoligonoRegular c = new PoligonoRegular(7,3.0); // Error!!! clase abstracta
System.out.println(c.area());
}
}
Clases Abstractas
Sí podemos, en cambio, hacer clases derivadas como la siguiente: Cuadrado.java
public class Cuadrado extends PolígonoRegular {
Aviso: La subclase de una clase
public Cuadrado(double lado) { abstracta debe incluir todos los
super(4,lado); métodos declarados como
} abstractos (o ser ella misma
public double área() { abstracta).
return lado * lado; Puede parecer que las clases
} abstractas son inútiles ¿para qué
} definir una clase que no se puede
Con su correspondiente programa principal:Principal.java usar sino a través de otras? Sin
public class Principal { embargo son útiles para conseguir
un buen diseño de una aplicación;
public static void main(String[] args) { en la clase abstracta incluimos
Cuadrado c = new Cuadrado(3.0); código que será común a todo un
System.out.println(c.área()); conjunto de clases (las que
System.out.println(c.perímetro()); derivarán de ellas) y además
} indicamos qué métodos deben
escribir las clases hijas para
} completarlas.
Interfaces
Un interface es una colección de declaraciones de métodos (sin definirlos) y
también puede incluir constantes.
Runnable es un ejemplo de interface en el cual se declara, pero no se
implemementa, una función miembro run.
Aviso: Las clases que implementen
(implements) la interface Runnable
public interface Runnable { han de definir obligatoriamente la
public abstract void run(); función run.
}
El papel del interface es el de describir algunas de
class Animacion implements Runnable{ las características de una clase. Por ejemplo, el
public void run(){ hecho de que una persona sea un futbolista no
//define la función run define su personalidad completa, pero hace que
} tenga ciertas características que las distinguen de
} otras.

Clases que no están relacionadas pueden implementar el interface Runnable, por


ejemplo, una clase que describa una animación, y también puede implementar el
interface Runnable una clase que realice un cálculo intensivo.
Diferencias entre un interface y una clase
abstracta
Un interface es simplemente una lista de métodos no implementados, además
puede incluir la declaración de constantes. Una clase abstracta puede incluir
métodos implementados y no implementados o abstractos, miembros dato
constantes y otros no constantes.

Ahora bien, la diferencia es mucho más profunda y debemos tener en cuenta que a
diferencia de C , el lenguaje Java no tiene herencia múltiple.

Una clase solamente puede derivar (con extends) de una clase madre, pero puede
implementar varias interfaces. Los nombres de los interfaces se colocan separados
por una coma después de la palabra reservada implements.

El lenguaje Java no fuerza por tanto, una relación jerárquica, simplemente permite
que clases no relacionadas puedan tener algunas características de su
comportamiento similares.
Los interfaces y el polimorfismo

En el lenguaje C++, es posible la herencia múltiple, pero este tipo de herencia


presenta dificultades. Por ejemplo, cuando dos clases B y C derivan de una clase
base A, y a su vez una clase D deriva de B y C. Este problema es conocido con el
nombre de diamante.

En el lenguaje Java solamente existe la herencia simple, pero las clases pueden
implementar interfaces. Vamos a ver en este apartado que la importancia de los
interfaces no estriba en resolver los problemas inherentes a la herencia múltiple
sin forzar relaciones jerárquicas, sino es el de incrementar el polimorfismo del
lenguaje más allá del que proporciona la herencia simple.
Herencia simple

Creamos una clase abstracta denominada Animal de la cual deriva las clases Gato
y Perro. Ambas clases redefinen la función habla declarada abstracta en la clase
base Animal.

public abstract class Animal {


public abstract void habla();
}
class Perro extends Animal{
public void habla(){
System.out.println("¡Guau!");
}
}
class Gato extends Animal{
public void habla(){
System.out.println("¡Miau!");
}
}
Herencia simple
El polimorfismo nos permite pasar la referencia a un objeto de la clase Gato a una función
hazleHablar que conoce al objeto por su clase base Animal.
El polimorfismo nos ayuda a hacer el programa
public class PoliApp {
más flexible, por que en el futuro podemos
public static void main(String[] args) {
añadir nuevas clases derivadas de Animal, sin
Gato gato=new Gato(); que cambie para nada el método hazleHablar.
hazleHablar(gato); Como ejercicio, se sugiere al lector añadir la
} clase Pajaro a la jerarquía, y pasar un objeto de
static void hazleHablar(Animal sujeto){ dicha clase a la función hazleHablar para que
sujeto.habla(); se imprima ¡pio, pio, pio ..!.
}
}

El compilador no sabe exactamente que objeto se le pasará a la función hazleHablar en el


momento de la ejecución del programa. Si se pasa un objeto de la clase Gato se imprimirá
¡Miau!, si se pasa un objeto de la clase Perro se imprimirá ¡Guau!. El compilador solamente
sabe que se le pasará un objeto de alguna clase derivada de Animal. Por tanto, el
compilador no sabe que función habla será llamada en el momento de la ejecución del
programa.
Interfaces
Vamos a crear un interface denominado Parlanchin que contenga la declaración de una
función denominada habla

public interface Parlanchin {


public abstract void habla(); Hacemos que la jerarquía de clases que deriva
} de Animal implemente el interface Parlanchin

public abstract class Animal implements Parlanchin{


public abstract void habla();
}

class Perro extends Animal{


public void habla(){ System.out.println("¡Guau!"); }
}

class Gato extends Animal{


public void habla(){ System.out.println("¡Miau!"); }
}
Interfaces
Ahora veamos otra jerarquía de clases completamente distinta, la que deriva de la
clase base Reloj. Una de las clases de dicha jerarquía Cucu implementa el interface
Parlanchin y por tanto, debe de definir obligatoriamente la función habla
declarada en dicho interface.

public abstract class Reloj implements Parlanchin{


public abstract void habla();
}

class Cucu extends Reloj {


public void habla(){
System.out.println("¡Cucu, cucu, ..!");
}
}
Interfaces
Definamos la función hazleHablar de modo que conozca al objeto que se le pasa
no por una clase base, sino por el interface Parlanchin. A dicha función le
podemos pasar cualquier objeto que implemente el interface Parlanchin, este o
no en la misma jerarquía de clases.
Al ejecutar el programa, veremos que se
imprime en la consola ¡Miau!, por que a
public class PoliApp { la función hazleHablar se le pasa un
public static void main(String[] args) { objeto de la clase Gato, y después ¡Cucu,
Gato gato=new Gato(); hazleHablar(gato); cucu, ..! por que a la función hazleHablar
Cucu cucu=new Cucu(); hazleHablar(cucu); se le pasa un objeto de la clase Cucu.
}
static void hazleHablar(Parlanchin sujeto){
sujeto.habla();
} Si solamente hubiese herencia simple, Cucu tendría que derivar de la clase Animal (lo
} que no es lógico) o bien no se podría pasar a la función hazleHablar. Con interfaces,
cualquier clase en cualquier familia puede implementar el interface Parlanchin, y se
podrá pasar un objeto de dicha clase a la función hazleHablar. Esta es la razón por la
cual los interfaces proporcionan más polimorfismo que el que se puede obtener de
una simple jerarquía de clases.
• Lic. Martín J. Vargas

You might also like