INTERFACES
Introducción
Las interfaces
Java son expresiones puras de diseño. Se trata de auténticas conceptualizaciones
no implementadas que sirven de guía para definir un determinado concepto (clase)
y lo que debe hacer, pero sin desarrollar un mecanismo de solución.
Se trata de
declarar métodos abstractos y constantes que posteriormente puedan ser
implementados de diferentes maneras según las necesidades de un
programa.
Por ejemplo una
misma interfaz podría ser implementada en una versión de prueba de manera poco
óptima, y ser acelerada convenientemente en la versión definitiva tras conocer
más a fondo el problema.
Declaración
Para declarar
una interfaz se utiliza la sentencia interface, de la misma manera que se
usa la sentencia class:
interface
MiInterfaz {
int CONSTANTE =
100;
int
metodoAbstracto( int parametro );
}
Se observa en la
declaración que las variables adoptan la declaración en mayúsculas, pues en
realidad actuarán como constantes final. En ningún caso estas variables
actuarán como variables de instancia.
Por su parte,
los métodos tras su declaración presentan un punto y coma, en lugar de su cuerpo
entre llaves. Son métodos abstractos, por tanto, métodos sin
implementación
Implementación
de una interfaz
Como ya se ha
visto, las interfaces carecen de funcionalidad por no estar implementados sus
métodos, por lo que se necesita algún mecanismo para dar cuerpo a sus
métodos.
La palabra
reservada implements utilizada en la declaración de una clase indica que
la clase implementa la interfaz, es decir, que asume las constantes de la
interfaz, y codifica sus métodos:
class
ImplementaInterfaz implements MiInterfaz{
int
multiplicando=CONSTANTE;
int
metodoAbstracto( int parametro ){
return (
parametro * multiplicando );
}
}
En este ejemplo
se observa que han de codificarse todos los métodos que determina la interfaz
(metodoAbstracto()), y la validez de las constantes (CONSTANTE)
que define la interfaz durante toda la declaración de la clase.
Una interfaz no
puede implementar otra interfaz, aunque sí extenderla (extends)
ampliándola.
Herencia
múltiple
Java es un
lenguaje que incorpora herencia simple de implementación pero que puede aportar
herencia múltiple de interfaz. Esto posibilita la herencia múltiple en el diseño
de los programas Java.
Una interfaz
puede heredar de más de una interfaz antecesora.
interface InterfazMultiple extends Interfaz1,Interfaz2{
}
Una clase no
puede tener más que una clase antecesora, pero puede implementar más de una
interfaz:
class MiClase
extends SuPadre implements Interfaz1,Interfaz2{ }
Imagen 6:
Ejemplo de herencia múltiple
Para poder
llevar a cabo un esquema como el anterior en Java es necesario que las clases A,
B y C de la figura sean interfaces, y que la clase D sea una clase (que recibe
la herencia múltiple):
interface A{ }
interface B extends A{ }
interface C extends A{ }
Colisiones en la
herencia múltiple
En una herencia
múltiple, los identificadores de algunos métodos o atributos pueden coincidir en
la clase que hereda, si dos de las interfaces padres tienen algún método o
atributo que coincida en nombre. A esto se le llama
colisión.
Esto se dará
cuando las clases padre (en el ejemplo anterior B y C) tienen un
atributo o método que se llame igual. Java resuelve el problema estableciendo
una serie de reglas.
Para la colisión
de nombres de atributos, se obliga a especificar a qué interfaz base pertenecen
al utilizarlos.
Para la colisión
de nombres en métodos:
- Si tienen el mismo nombre y diferentes parámetros: se produce sobrecarga de métodos permitiendo que existan varias maneras de llamar al mismo.
- Si sólo cambia el valor devuelto: se da un error de compilación, indicando que no se pueden implementar los dos.
- Si coinciden en su declaración: se elimina uno de los dos, con lo que sólo queda uno.
Envolturas de
los tipos simples
Los tipos de
datos de Java no forman parte de la jerarquía de objetos. Sin embargo a veces es
necesario crear una representación como objeto de alguno de los tipos de datos
simples de Java.
La API de Java
contiene un conjunto de interfaces especiales para modificar el comportamiento
de los tipos de datos simple. A estas interfaces se las conoce como
envolturas de tipo simple.
Todas ellas son
hijas de la clase abstracta Number y son:
- Double: Da soporte al tipo double.
- Float: Da soporte al tipo float.
- Integer: Da soporte a los tipos int, short y byte.
- Long: Da soporte al tipo long.
- Character: Envoltura del tipo char.
- Boolean: Envoltorio al tipo boolean.
Los
métodos abstractos son útiles cuando se quiere que cada implementación de la
clase parezca y funcione igual, pero necesita que se cree una nueva clase para
utilizar los métodos abstractos. Los interfaces proporcionan un mecanismo para
abstraer los métodos a un nivel superior, lo que permite simular la herencia
múltiple de otros lenguajes.
Un interfaz sublima el concepto de clase abstracta hasta su
grado más alto. Un interfaz podrá verse simplemente como una forma, es como un
molde, solamente permite declarar nombres de métodos, listas de argumentos,
tipos de retorno y adicionalmente miembros datos (los cuales podrán ser
únicamente tipos básicos y serán tomados como constantes en tiempo de
compilación, es decir, static y final).
Un interfaz contiene una colección de métodos que se
implementan en otro lugar. Los métodos de una clase son public, static y
final.
La principal diferencia entre interface y
abstract es que un interfaz proporciona un mecanismo de encapsulación de
los protocolos de los métodos sin forzar al usuario a utilizar la herencia. Por
ejemplo:
public interface VideoClip {
// comienza la reproduccion del video
void play();
// reproduce el clip en un bucle
void bucle();
// detiene la reproduccion
void stop();
}
Las clases que quieran utilizar el interfaz
VideoClip utilizarán la palabra implements y proporcionarán el código
necesario para implementar los métodos que se han definido para el
interfaz:
class MiClase implements VideoClip {
void play() {
<código>
}
void bucle() {
<código>
}
void stop() {
<código>
}
Al utilizar implements para el interface es como si se
hiciese una acción de copiar-y-pegar del código del interface, con lo
cual no se hereda nada, solamente se pueden usar los métodos.
La ventaja principal del uso de interfaces es que una clase
interface puede ser implementada por cualquier número de clases,
permitiendo a cada clase compartir el interfaz de programación sin tener que ser
consciente de la implementación que hagan las otras clases que implementen el
interface.
class MiOtraClase implements VideoClip {
void play() {
<código nuevo>
}
void bucle() {
<código nuevo>
}
void stop() {
<código nuevo>
}
Es decir, el aspecto más importante del uso de interfaces
es que múltiples objetos de clases diferentes pueden ser tratados como si fuesen
de un mismo tipo común, donde este tipo viene indicado por el nombre del
interfaz.
Aunque se puede considerar el nombre del interfaz como un
tipo de prototipo de referencia a objetos, no se pueden instanciar objetos en sí
del tipo interfaz. La definición de un interfaz no tiene constructor, por lo que
no es posible invocar el operador new sobre un tipo interfaz.
Un interfaz puede heredar de varios interfaces sin ningún
problema. Sin embargo, una clase solamente puede heredar de una clase base, pero
puede implementar varios interfaces. También, el JDK ofrece la posibilidad de
definir un interfaz vacío, como es el caso de Serialize, que permite
serializar un objeto. Un interfaz vacío se puede utilizar como un flag,
un marcador para marcar a una clase con una propiedad determinada.
La aplicación java514.java, ilustra algunos de los conceptos referentes a los
interfaces. Se definen dos interfaces, en uno de ellos se definen dos constantes
y en el otro se declara un método put() y un método get(). Las
constantes y los métodos se podrían haber colocado en la misma definición del
interfaz, pero se han separado para mostrar que una clase simple puede
implementar dos o más interfaces utilizando el separador coma (,) en la lista de
interfaces.
También se definen dos clases, implementando cada una de
ellas los dos interfaces. Esto significa que cada clase define el método
put() y el método get(), declarados en un interfaz y hace uso de
las constantes definidas en el otro interfaz. Estas clase se encuentran en
ficheros separados por exigencias del compilador, los ficheros son
Constantes.java y MiInterfaz.java, y el contenido de ambos ficheros es el que se muestra a
continuación:
public interface Constantes {
public final double pi = 6.14;
public final int constanteInt = 125;
}
public interface MiInterfaz {
void put( int dato );
int get();
}
Es importante observar que en la definición de los dos
métodos del interfaz, cada clase los define de la forma más adecuada para esa
clase, sin tener en cuenta cómo estará definidos en las otras
clases.
Una de las clases también define el método show(),
que no está declarado en el interfaz. Este método se utiliza para demostrar que
un método que no está declarado en el interfaz no puede ser accedido utilizando
una variable referencia de tipo interfaz.
El método main() en la clase principal ejecuta una
serie de instanciaciones, invocaciones de métodos y asignaciones destinadas a
mostrar las características de los interfaces descritos anteriormente. Si se
ejecuta la aplicación, las sentencias que se van imprimiendo en pantalla son
autoexplicactivas de lo que está sucediendo en el corazón de la
aplicación.
Los interfaces son útiles para recoger las similitudes
entre clase no relacionadas, forzando una relación entre ellas. También para
declarar métodos que forzosamente una o más clases han de implementar. Y
también, para tener acceso a un objeto, para permitir el uso de un objeto sin
revelar su clase, son los llamados objetos anónimos, que son muy útiles
cuando se vende un paquete de clases a otros desarrolladores.
No hay comentarios:
Publicar un comentario