domingo, 26 de febrero de 2012

4.3 Definición, implementación y herencia de interfaces

Para descargar el documento de este tema, haz clic aquí

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{ }
El ejemplo típico de herencia múltiple es el que se presenta con la herencia en diamante:
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{ }
class D implements B,C{ }

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