¿Hay más en una interfaz que tener los métodos correctos?

159

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?

Haga clic en Upvote
fuente
2
Recuerde, las interfaces no son específicas de Java. Todos los lenguajes OOP los tienen de una forma u otra, aunque no siempre se definen de manera tan explícita como Java.
Herms
2
Técnicamente, todos los lenguajes OOP fuertemente tipados los tienen de una forma u otra. Los idiomas sin tipo, o tipo pato, no tienen un concepto similar.
Jared
1
@ Jared ¿No estás confundiendo la escritura fuerte con la escritura estática, y "sin tipo" con la escritura dinámica?
eljenso
El polimorfismo también se puede lograr a través de interfaces. Consulte la última sección de esta página codenuggets.com/2014/06/20/java-interface
Jeff

Respuestas:

143

Las interfaces son una forma de hacer que su código sea más flexible. Lo que haces es esto:

Ibox myBox=new Rectangle();

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:

Ibox myBox=new OtherKindOfBox();

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:

myBox.close()

(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.

Morgangandes
fuente
54
No hay nada en esta respuesta que sea exclusivo de las interfaces Java . Lo mismo se aplica igualmente a las clases abstractas, o incluso a las concretas. Esperaría una buena respuesta para mencionar la capacidad de implementar múltiples interfaces, y cuándo / por qué eso sería útil.
Rogério
16
¿Cómo se seleccionó esto como respuesta? Es una breve descripción de por qué el polimorfismo es útil, pero como decía el póster anterior, esperaría una mejor explicación de múltiples interfaces y aún más importante cuando es apropiado usar una interfaz frente a una clase abstracta.
trevorkavanaugh
2
Esto tiene muy poco que ver con la explicación de las interfaces y todo lo que tiene que ver con los principios básicos del polimorfismo
A-Developer-Has-No-Name
123

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.Collectionsque proporciona todo tipo de métodos útiles que operan exclusivamente en interfaces, como sort()o reverse()para List. El punto aquí es que este código ahora se puede usar para ordenar o revertir cualquier clase que implemente las Listinterfaces, no solo ArrayListy LinkedList, sino también clases que usted mismo escriba, que pueden implementarse de una manera que las personas que escribieron java.util.Collectionsnunca 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.

Michael Borgwardt
fuente
9
Esa es una respuesta bastante buena, me gusta cuando das ejemplos de clases de paquetes java ...
Owais Qureshi
1
Me gustóyou can write code that operates on well-known interfaces, or interfaces you define
Manish Kumar
Espere un momento ... ¿Qué hace que las interfaces sean útiles no es [la capacidad de usar cualquier implementación que desee], sino más bien [la capacidad de usar cualquier implementación que desee]? Sin embargo, mencionar el caso opuesto es más o menos un buen punto.
Powerslave
44
@Powerslave: parafrasearlo más como Lo que hace que las interfaces sean útiles no es [la capacidad de escribir código donde tiene que cambiar solo una línea al cambiar la impedancia] sino más bien [la capacidad de escribir código donde ni siquiera especifica una implementación en todas].
Michael Borgwardt
@MichaelBorgwardt Eso suena mucho mejor. :) ¡Gracias por aclararlo!
Powerslave
119

Uno de los muchos usos que he leído es donde es difícil sin múltiples interfaces de uso de herencia en Java:

class Animal
{
void walk() { } 
....
.... //other methods and finally
void chew() { } //concentrate on this
} 

Ahora, imagine un caso donde:

class Reptile extends Animal 
{ 
//reptile specific code here
} //not a problem here

pero,

class Bird extends Animal
{
...... //other Bird specific code
} //now Birds cannot chew so this would a problem in the sense Bird classes can also call chew() method which is unwanted

Mejor diseño sería:

class Animal
{
void walk() { } 
....
.... //other methods 
} 

Animal no tiene el método chew () y en su lugar se coloca en una interfaz como:

interface Chewable {
void chew();
}

y que la clase Reptile implemente esto y no Birds (ya que Birds no puede masticar):

class Reptile extends Animal implements Chewable { } 

y en caso de pájaros simplemente:

class Bird extends Animal { }
molesto
fuente
66
@CHEBURASHKA Y mal nombre. Si Reptile"mastica", entonces no es "masticable". La convención de (a veces) nombrar interfaces Whateverable solo debe aplicarse donde tiene mucho sentido. Nombrar la interfaz Predatorsería más apropiado aquí.
Powerslave
66
@Powerslave Es correcto en mi humilde opinión, un reptil es "capaz de masticar" / "masticable". Un halcón es un depredador, pero aún no puede masticar ... solo el picoteo pero "masticable" se puede definir mejor en la documentación de la interfaz.
Madmenyo
Excelente ... Explicado muy bien. Gracias..!
Gurusinghe
1
No lo entiendo Todo lo que parece es que las interfaces son una buena manera de asegurarse de implementar los mismos métodos en cada clase que lo implemente (por ejemplo, me impide tomar la estúpida elección de una clase Bird con run () y una clase Dog con runn (), son todos iguales). Pero al prestar atención y hacer que mis clases tengan los mismos formatos / estructuras de método, ¿no podría lograr lo mismo? Realmente parece que las interfaces solo se aseguran de que el programador no sea olvidadizo. Además, las interfaces no parecen ahorrarme tiempo; Todavía necesito definir el método en cada clase que lo implementa.
Alex G
@AlexG: le dije a uno de los muchos usos, amigo :) ¡Hay más, apenas habíamos arañado la superficie para responder la pregunta de una manera simple!
molesto
47

El propósito de las interfaces es el polimorfismo , también conocido como sustitución de tipo . Por ejemplo, dado el siguiente método:

public void scale(IBox b, int i) {
   b.setSize(b.getSize() * i);
}

Al llamar al scalemétodo, puede proporcionar cualquier valor que sea de un tipo que implemente la IBoxinterfaz. En otras palabras, si Rectangley Squareambos se implementan IBox, puede proporcionar una Rectangleo una Squaredonde sea que IBoxse espera una.

Apocalipsis
fuente
8
¿Por qué el propósito de las interfaces es polimorfismo, si ya puedo lograrlo en Java con la subclasificación y la anulación de métodos?
eljenso
1
Es lo mismo, excepto que las interfaces deben omitir cualquier implementación. Por lo tanto, las clases pueden implementar más de una interfaz.
Apocalisp
44
Oye, nunca dije que Java tuviera ningún tipo de integridad conceptual. La sustitución de tipos es el propósito de todo subtipo. Java tiene más de un mecanismo de subtipo, ninguno de los cuales es particularmente bueno.
Apocalisp
1
Nunca dije nada acerca de la integridad conceptual también. Pero sigamos adelante. Si puede escalar cada IBox con su método, ¿no debería ser una operación declarada en IBox: IBox.scale (int)?
eljenso
1
No queremos unir Integer a IBox, por eso no lo convertimos en un método en Integer. Y la cantidad de métodos en una interfaz se decide por la consistencia y la cohesión de la abstracción que expresa, no por lo engorroso que sería implementarla. De todos modos, gracias por tus respuestas Apo.
eljenso
33

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:

|anAnimal|    
anAnimal := Pig new.
anAnimal makeNoise.

anAnimal := Cow new.
anAnimal makeNoise.

Ese código:

  1. Declara una variable local llamada anAnimal (tenga en cuenta que NO especificamos el TIPO de la variable; todas las variables son referencias a un objeto, ni más ni menos).
  2. Crea una nueva instancia de la clase llamada "Pig"
  3. Asigna esa nueva instancia de Pig a la variable anAnimal.
  4. Envía el mensaje makeNoiseal cerdo.
  5. Repite todo usando una vaca, pero asignándola a la misma variable exacta que el Cerdo.

El mismo código Java se vería así (suponiendo que Duck y Cow son subclases de Animal:

Animal anAnimal = new Pig();
duck.makeNoise();

anAnimal = new Cow();
cow.makeNoise();

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:

|aFarmObject|
aFarmObject := Cow new.
aFarmObject grow.
aFarmObject makeNoise.

aFarmObject := Corn new.
aFarmObject grow.
aFarmObject harvest.

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:

List<Growable> list = new ArrayList<Growable>();
list.add(new Cow());
list.add(new Corn());
list.add(new Pig());

for(Growable g : list) {
   g.grow();
}

Y nos permite hacer esto, hacer ruidos de animales:

List<Animal> list = new ArrayList<Animal>();
list.add(new Cow());
list.add(new Pig());
for(Animal a : list) {
  a.makeNoise();
}

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:

|aFarmObject|
aFarmObject := Corn new.
aFarmObject makeNoise. // No compiler error - not checked until runtime.

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:

// Compiler error: Corn cannot be cast to Animal.
Animal farmObject = new Corn();  
farmObject makeNoise();

-

// Compiler error: Animal doesn't have the harvest message.
Animal farmObject = new Cow();
farmObject.harvest(); 

Entonces ... para resumir:

  1. 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).

  2. Las interfaces nos brindan muchos de los beneficios del polimorfismo "verdadero", sin sacrificar la verificación del tipo de compilador.

Jared
fuente
2
Este es el texto de mi respuesta a otra pregunta: stackoverflow.com/questions/379282/… . Pero, son respuestas relacionadas.
Jared
2
Entonces, puedo preguntar, ¿cómo distingue un lenguaje tipeado de pato entre Animal.water () (el cual, el granjero mojigato solía decir que se filtra) y Plant.water () que usa para regar las plantas. La ambigüedad es el enemigo. Cualquier cantidad de verbosidad necesaria para superar la ambigüedad es IMO aceptable.
Bill K
1
Sí ... ambigüedad es el nombre del juego con los idiomas escritos en pato. Cuando se trabaja profesionalmente en un lenguaje de tipo pato, no es raro ver miembros (métodos y variables) con nombres de 50-100 caracteres de longitud.
Jared
1
Otro gran inconveniente de los lenguajes de tipo pato es la incapacidad de realizar una refactorización programática basada en análisis estático: intente pedir una imagen de Smalltalk para la lista de todas las personas que llaman de su método printString ... obtendrá la lista de todas las personas que llaman de TODOS los métodos de printString. ...
Jared
... porque la persona que llama de Automobile # printString no se puede diferenciar programáticamente de la persona que llama de NearEarthOrbit # printString.
Jared
9

Normalmente, las interfaces definen la interfaz que debe usar (como su nombre lo dice ;-)). Muestra


public void foo(List l) {
   ... do something
}

Ahora su función fooacepta ArrayLists, LinkedLists, ... no solo un tipo.

¡Lo más importante en Java es que puede implementar múltiples interfaces pero solo puede extender UNA clase! Muestra:


class Test extends Foo implements Comparable, Serializable, Formattable {
...
}
es posible pero

class Test extends Foo, Bar, Buz {
...
}
¡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) de Rectangle.

Johannes Weiss
fuente
1
¿Se supone que 'List' es un miembro de la interfaz?
Haga clic en Upvote
1
List es una interfaz en la biblioteca de colecciones java.
rmeador 02 de
La lista es una interfaz en la biblioteca estándar de Java ( java.sun.com/javase/6/docs/api/java/util/List.html ). Solo lo está usando para ilustrar su punto.
Michael Myers
6

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.

Ickster
fuente
6

Podrías hacerlo

Ibox myBox = new Rectangle();

de esa manera estás usando este objeto como Ibox y no te importa que sea realmente Rectangle.

Adaptador IA
fuente
¿Eso significa que podríamos escribir así? > Rectángulo inst = nuevo Rectángulo ();
Dr.jacky
@ Mr.Hyde Si luego desea agregar Square, tendría un problema ... si intenta hacerlo sin interfaces, no puede garantizar eso Squarey Rectangletiene 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.
Kolob Canyon
6

¿POR QUÉ INTERFAZ ??????

Comienza con un perro. En particular, un pug .

El pug tiene varios comportamientos:

public class Pug { 
private String name;
public Pug(String n) { name = n; } 
public String getName() { return name; }  
public String bark() { return  "Arf!"; } 
public boolean hasCurlyTail() { return true; } }

Y tienes un Labrador, que también tiene un conjunto de comportamientos.

public class Lab { 
private String name; 
public Lab(String n) { name = n; } 
public String getName() { return name; } 
public String bark() { return "Woof!"; } 
public boolean hasCurlyTail() { return false; } }

Podemos hacer algunos pugs y laboratorios:

Pug pug = new Pug("Spot"); 
Lab lab = new Lab("Fido");

Y podemos invocar sus comportamientos:

pug.bark() -> "Arf!" 
lab.bark() -> "Woof!" 
pug.hasCurlyTail() -> true 
lab.hasCurlyTail() -> false 
pug.getName() -> "Spot"

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 :

public class Kennel { 
Pug[] pugs = new Pug[10]; 
Lab[] labs = new Lab[10];  
public void addPug(Pug p) { ... } 
public void addLab(Lab l) { ... } 
public void printDogs() { // Display names of all the dogs } }

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.

public interface Dog 
{
public String bark(); 
public String getName(); 
public boolean hasCurlyTail(); }

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.

public class Pug implements Dog {
// the rest is the same as before } 

public class Lab implements Dog { 
// the rest is the same as before 
}

Todavía puedo crear instancias de Pugs y Labs como lo hice anteriormente, pero ahora también tengo una nueva forma de hacerlo:

Dog d1 = new Pug("Spot"); 
Dog d2 = new Lab("Fido");

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:

d1.bark() -> "Arf!" 
d2.bark() -> "Woof!" 
d1.hasCurlyTail() -> true 
d2.hasCurlyTail() -> false 
d1.getName() -> "Spot"

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.

public class Kennel {
Dog[] dogs = new Dog[20]; 
public void addDog(Dog d) { ... } 
public void printDogs() {
// Display names of all the dogs } }

Aquí se explica cómo usarlo:

Kennel k = new Kennel(); 
Dog d1 = new Pug("Spot"); 
Dog d2 = new Lab("Fido"); 
k.addDog(d1); 
k.addDog(d2); 
k.printDogs();

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.

niranjan kurambhatti
fuente
@niranjan kurambhatti puedo hacer todas las clases para extender el perro, pero aún así ¿por qué interfaz?
Jeeva
3

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 una Vectoro una ArrayListo una HashListo lo que sea. Y puede pasar eso Lista cualquier función que requiera una interfaz Collectiono Iterabletambién.

Esto hace que las funciones sean Collections.sort(List list)posibles, independientemente de cómo Listse implemente.

Dormir
fuente
3

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).

Christopher Smith
fuente
1
Estás confundiendo la escritura fuerte con la escritura estática.
eljenso
3

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

public interface Saveable {
....

public interface Printable {
....

etc. (Los esquemas de nombres no siempre funcionan, por ejemplo, no estoy seguro de que Boxablesea ​​apropiado aquí)

Brian Agnew
fuente
3

¿El único propósito de las interfaces es asegurarse de que la clase que implementa una interfaz tenga los métodos correctos descritos por una interfaz? ¿O hay algún otro uso de interfaces?

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

  1. firmas de método
  2. métodos predeterminados
  3. métodos estáticos
  4. definiciones constantes

Los únicos métodos que tienen implementaciones son los métodos predeterminados y estáticos.

Usos de la interfaz :

  1. Para definir un contrato
  2. Para vincular clases no relacionadas tiene capacidades (por ejemplo, las clases que implementan la Serializableinterfaz pueden o no tener alguna relación entre ellas, excepto la implementación de esa interfaz
  3. Para proporcionar una implementación intercambiable , por ejemplo, un patrón de estrategia
  4. Los métodos predeterminados le permiten agregar nuevas funcionalidades a las interfaces de sus bibliotecas y garantizar la compatibilidad binaria con el código escrito para versiones anteriores de esas interfaces
  5. Organice métodos auxiliares en sus bibliotecas con métodos estáticos (puede mantener métodos estáticos específicos para una interfaz en la misma interfaz en lugar de en una clase separada)

Algunas 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 .

Ravindra babu
fuente
Eliminé la etiqueta java-8 ya que la pregunta no hacía nada sobre java-8 (y en realidad se me preguntó mucho antes que java-8). Las etiquetas son para preguntas, no para respuestas.
Tagir Valeev
2

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 interfacepara expresar esto en Java.

eljenso
fuente
El propósito de toda programación estructurada es la abstracción. ¿Por qué diría que el propósito de las interfaces es la abstracción, ya que puedo lograr exactamente lo mismo usando genéricos y composición de clases?
Apocalisp
1
Si toda la programación estructurada es abstracción (su reclamo), entonces las interfaces son abstracciones en esa abstracción.
eljenso
1

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).

Todd R
fuente
1

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:


class Box{
    public int getSize(){
       return 0;
    }
    public int getArea(){
       return 1;
    }

}

class Triangle{
    public int getSize(){
       return 1;
    }
    public int getArea(){
       return 0;
    }

}

class FunckyFigure extends Box, Triable{
   // we do not implement the methods we will used the inherited ones
}

¿Cuál sería el método que debería llamarse cuando usamos


   FunckyFigure.GetArea(); 

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.

Mandel
fuente
Es posible que desee marcar una diferencia entre la herencia de implementación múltiple y la herencia de interfaz múltiple en su respuesta, de lo contrario, se vuelve confuso.
eljenso
0

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.

package mypack;

interface StorageDevice {
    void saveData (String data);
}


class FDD implements StorageDevice {
    public void saveData (String data) {
        System.out.println("Save to floppy drive! Data: "+data);
    }
}

class HDD implements StorageDevice {
    public void saveData (String data) {
        System.out.println("Save to hard disk drive! Data: "+data);
    }
}

class OperatingSystem {
    public String name;
    StorageDevice[] devices;
    public OperatingSystem(String name, StorageDevice[] devices) {

        this.name = name;
        this.devices = devices.clone();

        System.out.println("Running OS " + this.name);
        System.out.println("List with storage devices available:");
        for (StorageDevice s: devices) {
            System.out.println(s);
        }

    }

    public void saveSomeDataToStorageDevice (StorageDevice storage, String data) {
        storage.saveData(data);
    }
}

public class Main {

    public static void main(String[] args) {

        StorageDevice fdd0 = new FDD();
        StorageDevice hdd0 = new HDD();     
        StorageDevice[] devs = {fdd0, hdd0};        
        OperatingSystem os = new OperatingSystem("Linux", devs);
        os.saveSomeDataToStorageDevice(fdd0, "blah, blah, blah...");    
    }
}
Vladimir Georgiev
fuente
Lo mismo se puede hacer con la clase abstracta StorageDevice y las clases FDD y HDD que amplían la clase StorageDevice. pero si usamos la clase abstracta no podemos aprovechar la herencia múltiple.
Vladimir Georgiev