Entonces digamos que tengo esta interfaz:
public interface IBox
{
public void setSize(int size);
public int getSize();
public int getArea();
//...and so on
}
Y tengo una clase que lo implementa:
public class Rectangle implements IBox
{
private int size;
//Methods here
}
Si quisiera usar la interfaz IBox, en realidad no puedo crear una instancia de la misma:
public static void main(String args[])
{
Ibox myBox=new Ibox();
}
¿Derecha? Así que realmente tendría que hacer esto:
public static void main(String args[])
{
Rectangle myBox=new Rectangle();
}
Si eso es cierto, ¿entonces el único propósito de las interfaces es asegurarse de que la clase que implementa una interfaz tenga los métodos correctos tal como lo describe una interfaz? ¿O hay algún otro uso de interfaces?
java
oop
language-features
interface
Haga clic en Upvote
fuente
fuente
Respuestas:
Las interfaces son una forma de hacer que su código sea más flexible. Lo que haces es esto:
Luego, más tarde, si decide que desea usar un tipo diferente de cuadro (tal vez haya otra biblioteca, con un tipo mejor de cuadro), cambie su código a:
Una vez que te acostumbres, verás que es una excelente manera (en realidad esencial) de trabajar.
Otra razón es, por ejemplo, si desea crear una lista de cuadros y realizar alguna operación en cada uno, pero desea que la lista contenga diferentes tipos de cuadros. En cada cuadro puedes hacer:
(suponiendo que IBox tiene un método close ()) a pesar de que la clase real de myBox cambia según el cuadro en el que se encuentre en la iteración.
fuente
Lo que hace que las interfaces sean útiles no es el hecho de que "puede cambiar de opinión y usar una implementación diferente más tarde y solo tiene que cambiar el único lugar donde se crea el objeto". Eso no es un problema.
El punto real ya está en el nombre: definen una interfaz que cualquiera puede implementar para usar todo el código que opera en esa interfaz. El mejor ejemplo es el
java.util.Collections
que proporciona todo tipo de métodos útiles que operan exclusivamente en interfaces, comosort()
oreverse()
paraList
. El punto aquí es que este código ahora se puede usar para ordenar o revertir cualquier clase que implemente lasList
interfaces, no soloArrayList
yLinkedList
, sino también clases que usted mismo escriba, que pueden implementarse de una manera que las personas que escribieronjava.util.Collections
nunca imaginaron.De la misma manera, puede escribir código que opera en interfaces bien conocidas, o interfaces que defina, y otras personas pueden usar su código sin tener que pedirle que respalde sus clases.
Otro uso común de las interfaces es para Callbacks. Por ejemplo, java.swing.table.TableCellRenderer , que le permite influir en cómo una tabla Swing muestra los datos en una determinada columna. Implementa esa interfaz, pasa una instancia a
JTable
, y en algún momento durante la representación de la tabla, su código será llamado para hacer sus cosas.fuente
you can write code that operates on well-known interfaces, or interfaces you define
Uno de los muchos usos que he leído es donde es difícil sin múltiples interfaces de uso de herencia en Java:
Ahora, imagine un caso donde:
pero,
Mejor diseño sería:
Animal no tiene el método chew () y en su lugar se coloca en una interfaz como:
y que la clase Reptile implemente esto y no Birds (ya que Birds no puede masticar):
y en caso de pájaros simplemente:
fuente
Reptile
"mastica", entonces no es "masticable". La convención de (a veces) nombrar interfaces Whateverable solo debe aplicarse donde tiene mucho sentido. Nombrar la interfazPredator
sería más apropiado aquí.El propósito de las interfaces es el polimorfismo , también conocido como sustitución de tipo . Por ejemplo, dado el siguiente método:
Al llamar al
scale
método, puede proporcionar cualquier valor que sea de un tipo que implemente laIBox
interfaz. En otras palabras, siRectangle
ySquare
ambos se implementanIBox
, puede proporcionar unaRectangle
o unaSquare
donde sea queIBox
se espera una.fuente
Las interfaces permiten lenguajes tipados estáticamente para soportar el polimorfismo. Un purista orientado a objetos insistiría en que un lenguaje debe proporcionar herencia, encapsulación, modularidad y polimorfismo para ser un lenguaje orientado a objetos con todas las funciones. En lenguajes de tipo dinámico (o tipo pato), el polimorfismo es trivial (como Smalltalk); sin embargo, en lenguajes tipados estáticamente (como Java o C #), el polimorfismo está lejos de ser trivial (de hecho, en la superficie parece estar en desacuerdo con la noción de tipeo fuerte).
Déjame demostrarte:
En un lenguaje de tipo dinámico (o tipo pato) (como Smalltalk), todas las variables son referencias a objetos (nada menos y nada más). Entonces, en Smalltalk, puedo hacer esto:
Ese código:
makeNoise
al cerdo.El mismo código Java se vería así (suponiendo que Duck y Cow son subclases de Animal:
Eso está muy bien, hasta que presentamos la clase Vegetal. Las verduras tienen el mismo comportamiento que los animales, pero no todas. Por ejemplo, tanto Animal como Vegetal podrían crecer, pero claramente las verduras no hacen ruido y los animales no pueden ser cosechados.
En Smalltalk, podemos escribir esto:
Esto funciona perfectamente bien en Smalltalk porque está escrito en forma de pato (si camina como un pato y grazna como un pato, es un pato). En este caso, cuando se envía un mensaje a un objeto, se realiza una búsqueda en la lista de métodos del receptor, y si se encuentra un método coincidente, se llama. Si no, se produce algún tipo de excepción NoSuchMethodError, pero todo se realiza en tiempo de ejecución.
Pero en Java, un lenguaje de tipo estático, ¿qué tipo podemos asignar a nuestra variable? El maíz debe heredarse de los vegetales, para apoyar el crecimiento, pero no puede heredarse de los animales, porque no hace ruido. La vaca necesita heredar de Animal para soportar makeNoise, pero no puede heredar de Vegetal porque no debe implementar la cosecha. Parece que necesitamos herencia múltiple : la capacidad de heredar de más de una clase. Pero eso resulta ser una característica del lenguaje bastante difícil debido a todos los casos extremos que aparecen (¿qué sucede cuando más de una superclase paralela implementa el mismo método?, Etc.)
A lo largo vienen las interfaces ...
Si hacemos clases de animales y vegetales, con cada implementación de Growable, podemos declarar que nuestra vaca es animal y nuestro maíz es vegetal. También podemos declarar que tanto animal como vegetal son cultivables. Eso nos permite escribir esto para hacer crecer todo:
Y nos permite hacer esto, hacer ruidos de animales:
La ventaja del lenguaje de tipo pato es que obtienes un polimorfismo realmente agradable: todo lo que una clase tiene que hacer para proporcionar comportamiento es proporcionar el método. Mientras todos jueguen bien y solo envíen mensajes que coincidan con los métodos definidos, todo está bien. La desventaja es que el tipo de error a continuación no se detecta hasta el tiempo de ejecución:
Los lenguajes de tipo estático proporcionan una "programación por contrato" mucho mejor, porque detectarán los dos tipos de error a continuación en tiempo de compilación:
-
Entonces ... para resumir:
La implementación de la interfaz le permite especificar qué tipo de cosas pueden hacer los objetos (interacción) y la herencia de clase le permite especificar cómo se deben hacer las cosas (implementación).
Las interfaces nos brindan muchos de los beneficios del polimorfismo "verdadero", sin sacrificar la verificación del tipo de compilador.
fuente
Normalmente, las interfaces definen la interfaz que debe usar (como su nombre lo dice ;-)). Muestra
Ahora su función
foo
aceptaArrayList
s,LinkedList
s, ... no solo un tipo.¡Lo más importante en Java es que puede implementar múltiples interfaces pero solo puede extender UNA clase! Muestra:
es posible pero ¡no es!Su código anterior también podría ser:
IBox myBox = new Rectangle();
. Lo importante ahora es que myBox SOLO contiene los métodos / campos de IBox y no los otros métodos (posiblemente existentes) deRectangle
.fuente
Creo que comprende todo lo que hacen las interfaces, pero aún no se imagina las situaciones en las que una interfaz es útil.
Si está creando instancias, utilizando y liberando un objeto dentro de un alcance limitado (por ejemplo, dentro de una llamada a un método), una interfaz realmente no agrega nada. Como notó, la clase concreta es conocida.
Donde las interfaces son útiles es cuando un objeto necesita ser creado en un lugar y devuelto a una persona que llama que puede no preocuparse por los detalles de implementación. Cambiemos su ejemplo de IBox a una Forma. Ahora podemos tener implementaciones de Shape como Rectangle, Circle, Triangle, etc. Las implementaciones de los métodos getArea () y getSize () serán completamente diferentes para cada clase concreta.
Ahora puede usar una fábrica con una variedad de métodos createShape (params) que devolverán una Forma apropiada dependiendo de los parámetros pasados. Obviamente, la fábrica sabrá qué tipo de Forma se está creando, pero la persona que llama no tendrá para preocuparse por si es un círculo, un cuadrado, etc.
Ahora, imagine que tiene una variedad de operaciones que debe realizar en sus formas. Tal vez necesite ordenarlos por área, configurarlos a un nuevo tamaño y luego mostrarlos en una interfaz de usuario. Todas las formas son creadas por la fábrica y luego se pueden pasar a las clases Clasificador, Clasificador y Pantalla con mucha facilidad. Si necesita agregar una clase de hexágono en algún momento en el futuro, no tiene que cambiar nada más que la fábrica. Sin la interfaz, agregar otra forma se convierte en un proceso muy complicado.
fuente
Podrías hacerlo
de esa manera estás usando este objeto como Ibox y no te importa que sea realmente
Rectangle
.fuente
Square
, tendría un problema ... si intenta hacerlo sin interfaces, no puede garantizar esoSquare
yRectangle
tiene los mismos métodos ... esto puede resultar en una pesadilla cuando tiene una base de código más grande ... Recuerde, las interfaces definen una plantilla.¿POR QUÉ INTERFAZ ??????
Comienza con un perro. En particular, un pug .
El pug tiene varios comportamientos:
Y tienes un Labrador, que también tiene un conjunto de comportamientos.
Podemos hacer algunos pugs y laboratorios:
Y podemos invocar sus comportamientos:
Digamos que tengo una perrera y necesito hacer un seguimiento de todos los perros que estoy albergando. Yo necesito guardar mis doguillos y labradores en matrices independientes :
Pero esto claramente no es óptimo. Si quiero alojar algunos caniches , también, tengo que cambiar mi definición de Kennel para agregar una variedad de caniches. De hecho, necesito una matriz separada para cada tipo de perro.
Insight: tanto los pugs como los labradors (y caniches) son tipos de perros y tienen el mismo conjunto de comportamientos. Es decir, podemos decir (para los fines de este ejemplo) que todos los perros pueden ladrar, tener un nombre y pueden o no tener una cola rizada. Podemos usar una interfaz para definir lo que todos los perros pueden hacer, pero dejar que dependa de los tipos específicos de perros para implementar esos comportamientos particulares. La interfaz dice "aquí están las cosas que todos los perros pueden hacer", pero no dice cómo se hace cada comportamiento.
Luego modifico ligeramente las clases Pug y Lab para implementar los comportamientos del perro. Podemos decir que un Pug es un perro y un laboratorio es un perro.
Todavía puedo crear instancias de Pugs y Labs como lo hice anteriormente, pero ahora también tengo una nueva forma de hacerlo:
Esto dice que d1 no es solo un perro, es específicamente un Pug. Y d2 también es un perro, específicamente un laboratorio. Podemos invocar los comportamientos y funcionan como antes:
Aquí es donde todo el trabajo extra vale la pena. La clase Kennel se vuelve mucho más simple. Solo necesito una matriz y un método addDog. Ambos funcionarán con cualquier objeto que sea un perro; es decir, objetos que implementan la interfaz Dog.
Aquí se explica cómo usarlo:
La última declaración mostraría: Spot Fido
Una interfaz le brinda la capacidad de especificar un conjunto de comportamientos que todas las clases que implementan la interfaz compartirán en común. En consecuencia, podemos definir variables y colecciones (como matrices) que no tienen que saber de antemano qué tipo de objeto específico tendrán, solo que contendrán objetos que implementen la interfaz.
fuente
Un gran ejemplo de cómo se usan las interfaces se encuentra en el marco de Colecciones. Si escribe una función que toma un
List
, entonces no importa si el usuario pasa unaVector
o unaArrayList
o unaHashList
o lo que sea. Y puede pasar esoList
a cualquier función que requiera una interfazCollection
oIterable
también.Esto hace que las funciones sean
Collections.sort(List list)
posibles, independientemente de cómoList
se implemente.fuente
Esta es la razón por la que los patrones de fábrica y otros patrones de creación son tan populares en Java. Tiene razón en que sin ellos Java no proporciona un mecanismo listo para usar para una fácil abstracción de la creación de instancias. Aún así, obtienes abstracción en todas partes donde no creas un objeto en tu método, que debería ser la mayor parte de tu código.
Como comentario aparte, generalmente animo a las personas a no seguir el mecanismo "IRealname" para nombrar interfaces. Eso es algo de Windows / COM que pone un pie en la tumba de la notación húngara y realmente no es necesario (Java ya está fuertemente tipado, y el objetivo de tener interfaces es tenerlas lo más indistinguibles posible de los tipos de clase).
fuente
No olvide que en una fecha posterior puede tomar una clase existente y hacer que se implemente
IBox
, y luego estará disponible para todo su código de caja.Esto se vuelve un poco más claro si las interfaces se denominan -able . p.ej
etc. (Los esquemas de nombres no siempre funcionan, por ejemplo, no estoy seguro de que
Boxable
sea apropiado aquí)fuente
Estoy actualizando la respuesta con nuevas características de interfaz, que se han introducido con la versión de Java 8 .
Desde la página de documentación de Oracle en el resumen de la interfaz :
Una declaración de interfaz puede contener
Los únicos métodos que tienen implementaciones son los métodos predeterminados y estáticos.
Usos de la interfaz :
Serializable
interfaz pueden o no tener alguna relación entre ellas, excepto la implementación de esa interfazAlgunas preguntas SE relacionadas con respecto a la diferencia entre clase abstracta e interfaz y casos de uso con ejemplos de trabajo:
¿Cuál es la diferencia entre una interfaz y una clase abstracta?
¿Cómo debería haber explicado la diferencia entre una interfaz y una clase abstracta?
Eche un vistazo a la página de documentación para comprender las nuevas características agregadas en Java 8: métodos predeterminados y métodos estáticos .
fuente
El propósito de las interfaces es la abstracción o el desacoplamiento de la implementación.
Si introduce una abstracción en su programa, no le importan las posibles implementaciones. Está interesado en lo que puede hacer y no en cómo , y utiliza un
interface
para expresar esto en Java.fuente
Si tiene CardboardBox y HtmlBox (ambos implementan IBox), puede pasarlos a cualquier método que acepte un IBox. A pesar de que ambos son muy diferentes y no son completamente intercambiables, los métodos que no se preocupan por "abrir" o "cambiar el tamaño" aún pueden usar sus clases (tal vez porque les importa cuántos píxeles se necesitan para mostrar algo en una pantalla).
fuente
Interfaces donde se agrega una característica a Java para permitir la herencia múltiple. Sin embargo, los desarrolladores de Java se dieron cuenta de que tener herencia múltiple era una característica "peligrosa", por eso surgió la idea de una interfaz.
La herencia múltiple es peligrosa porque podría tener una clase como la siguiente:
¿Cuál sería el método que debería llamarse cuando usamos
Todos los problemas se resuelven con interfaces, porque sabes que puedes extender las interfaces y que no tendrán métodos de clasificación ... por supuesto, el compilador es bueno y te dice si no implementaste un método, pero me gusta pensar que es Un efecto secundario de una idea más interesante.
fuente
Aquí está mi comprensión de la ventaja de la interfaz. Corrígeme si estoy equivocado. Imagine que estamos desarrollando un sistema operativo y otro equipo está desarrollando los controladores para algunos dispositivos. Por eso, hemos desarrollado una interfaz StorageDevice. Tenemos dos implementaciones (FDD y HDD) proporcionadas por otro equipo de desarrolladores.
Luego tenemos una clase OperatingSystem que puede llamar a métodos de interfaz como saveData simplemente pasando una instancia de clase implementada en la interfaz StorageDevice.
La ventaja aquí es que no nos importa la implementación de la interfaz. El otro equipo hará el trabajo implementando la interfaz StorageDevice.
fuente