Nehmen wir also an, ich habe diese Schnittstelle:
public interface IBox
{
public void setSize(int size);
public int getSize();
public int getArea();
//...and so on
}
Und ich habe eine Klasse, die es implementiert:
public class Rectangle implements IBox
{
private int size;
//Methods here
}
Wenn ich die Schnittstelle IBox verwenden wollte, kann ich keine Instanz davon erstellen, wie folgt:
public static void main(String args[])
{
Ibox myBox=new Ibox();
}
richtig? Also müsste ich das tatsächlich tun:
public static void main(String args[])
{
Rectangle myBox=new Rectangle();
}
Wenn dies zutrifft, besteht der einzige Zweck von Schnittstellen darin, sicherzustellen, dass die Klasse, die eine Schnittstelle implementiert, die richtigen Methoden enthält, wie von einer Schnittstelle beschrieben. Oder gibt es eine andere Verwendung von Schnittstellen?
java
oop
language-features
interface
Klicken Sie auf Upvote
quelle
quelle
Antworten:
Schnittstellen sind eine Möglichkeit, Ihren Code flexibler zu gestalten. Was Sie tun, ist Folgendes:
Wenn Sie später entscheiden, dass Sie eine andere Art von Box verwenden möchten (möglicherweise gibt es eine andere Bibliothek mit einer besseren Art von Box), wechseln Sie Ihren Code zu:
Sobald Sie sich daran gewöhnt haben, werden Sie feststellen, dass dies eine großartige (eigentlich unverzichtbare) Arbeitsweise ist.
Ein weiterer Grund ist beispielsweise, wenn Sie eine Liste von Feldern erstellen und für jedes eine Operation ausführen möchten, die Liste jedoch verschiedene Arten von Feldern enthalten soll. Auf jeder Box können Sie Folgendes tun:
(vorausgesetzt, IBox hat eine close () -Methode), obwohl sich die tatsächliche Klasse von myBox ändert, je nachdem, in welchem Feld Sie sich in der Iteration befinden.
quelle
Was Schnittstellen nützlich macht, ist nicht die Tatsache, dass "Sie Ihre Meinung ändern und später eine andere Implementierung verwenden können und nur den einen Ort ändern müssen, an dem das Objekt erstellt wird". Das ist kein Problem.
Der eigentliche Punkt liegt bereits im Namen: Sie definieren eine Schnittstelle , die jeder implementieren kann, um den gesamten Code zu verwenden, der auf dieser Schnittstelle ausgeführt wird. Das beste Beispiel
java.util.Collections
bietet alle Arten von nützlichen Methoden, die ausschließlich auf Schnittstellen wiesort()
oderreverse()
für arbeitenList
. Der Punkt hier ist, dass dieser Code jetzt verwendet werden kann, um jede Klasse zu sortieren oder umzukehren , die dieList
Schnittstellen implementiert - nicht nurArrayList
undLinkedList
, sondern auch Klassen, die Sie selbst schreiben. Diese können auf eine Weise implementiert werden, die sich die Leute, die geschrieben haben,java.util.Collections
nie vorgestellt haben.Auf die gleiche Weise können Sie Code schreiben, der auf bekannten oder von Ihnen definierten Schnittstellen ausgeführt wird, und andere Personen können Ihren Code verwenden, ohne Sie bitten zu müssen, ihre Klassen zu unterstützen.
Eine andere häufige Verwendung von Schnittstellen sind Rückrufe. Beispiel: java.swing.table.TableCellRenderer , mit dem Sie beeinflussen können, wie eine Swing-Tabelle die Daten in einer bestimmten Spalte anzeigt. Sie implementieren diese Schnittstelle, übergeben eine Instanz an die
JTable
und irgendwann während des Renderns der Tabelle wird Ihr Code aufgerufen, um seine Aufgaben zu erledigen.quelle
you can write code that operates on well-known interfaces, or interfaces you define
Eine der vielen Anwendungen, die ich gelesen habe, ist, wo es ohne Java-Schnittstellen mit Mehrfachvererbung schwierig ist:
Stellen Sie sich nun einen Fall vor, in dem:
aber,
Besseres Design wäre:
Animal verfügt nicht über die Methode ________ () und wird stattdessen wie folgt in eine Schnittstelle eingefügt:
und lassen Sie die Reptilienklasse dies implementieren und nicht Vögel (da Vögel nicht kauen können):
und bei Vögeln einfach:
quelle
Reptile
"kaut", dann ist selbst nicht "kaubar". Die Konvention der (manchmal) Benennung von Schnittstellen Whateverable sollte nur dort angewendet werden, wo es durchaus Sinn macht. Die Benennung der SchnittstellePredator
wäre hier angemessener.Der Zweck von Schnittstellen ist Polymorphismus , auch bekannt als Typensubstitution . Zum Beispiel mit der folgenden Methode:
Beim Aufrufen der
scale
Methode können Sie einen beliebigen Wert angeben, der vom Typ ist, der dieIBox
Schnittstelle implementiert . Mit anderen Worten, wennRectangle
undSquare
beide implementierenIBox
, können Sie entweder aRectangle
oder aSquare
angeben, wo immer einIBox
erwartet wird.quelle
Mithilfe von Schnittstellen können statisch typisierte Sprachen den Polymorphismus unterstützen. Ein objektorientierter Purist würde darauf bestehen, dass eine Sprache Vererbung, Kapselung, Modularität und Polymorphismus bietet, um eine voll funktionsfähige objektorientierte Sprache zu sein. In dynamisch typisierten oder ententypisierten Sprachen (wie Smalltalk) ist Polymorphismus trivial; In statisch typisierten Sprachen (wie Java oder C #) ist Polymorphismus jedoch alles andere als trivial (tatsächlich scheint er an der Oberfläche im Widerspruch zu der Vorstellung einer starken Typisierung zu stehen.)
Lassen Sie mich demonstrieren:
In einer dynamisch typisierten (oder ententypisierten) Sprache (wie Smalltalk) sind alle Variablen Verweise auf Objekte (nicht weniger und nicht mehr). In Smalltalk kann ich also Folgendes tun:
Dieser Code:
makeNoise
an das Schwein.Der gleiche Java-Code würde ungefähr so aussehen (unter der Annahme, dass Duck und Cow Unterklassen von Animal sind:
Das ist alles schön und gut, bis wir die Klasse Gemüse einführen. Gemüse hat das gleiche Verhalten wie Tier, aber nicht alle. Zum Beispiel können sowohl Tiere als auch Gemüse wachsen, aber Gemüse macht eindeutig keinen Lärm und Tiere können nicht geerntet werden.
In Smalltalk können wir Folgendes schreiben:
Dies funktioniert in Smalltalk sehr gut, da es vom Typ Ente ist (wenn es wie eine Ente läuft und wie eine Ente quakt - es ist eine Ente). In diesem Fall wird beim Senden einer Nachricht an ein Objekt eine Suche durchgeführt die Methodenliste des Empfängers, und wenn eine übereinstimmende Methode gefunden wird, wird sie aufgerufen. Wenn nicht, wird eine Art NoSuchMethodError-Ausnahme ausgelöst - aber alles wird zur Laufzeit ausgeführt.
Aber in Java, einer statisch typisierten Sprache, welchen Typ können wir unserer Variablen zuweisen? Mais muss von Gemüse erben, um das Wachstum zu unterstützen, kann aber nicht von Tier erben, da er keinen Lärm macht. Kuh muss von Animal erben, um makeNoise zu unterstützen, kann aber nicht von Vegetable erben, da es keine Ernte implementieren sollte. Es sieht so aus, als ob wir mehrere Vererbungen benötigen - die Fähigkeit, von mehr als einer Klasse zu erben. Aufgrund all der Randfälle, die auftauchen (was passiert, wenn mehr als eine parallele Superklasse dieselbe Methode implementieren? Usw.), stellt sich heraus, dass dies eine ziemlich schwierige Sprachfunktion ist.
Es kommen Schnittstellen ...
Wenn wir Tier- und Gemüseklassen mit jeder Implementierung von Growable machen, können wir erklären, dass unsere Kuh Tier und unser Mais Gemüse ist. Wir können auch erklären, dass sowohl Tier als auch Gemüse anbaubar sind. Das lässt uns dies schreiben, um alles wachsen zu lassen:
Und damit können wir Tiergeräusche machen:
Der Vorteil der Sprache vom Typ Ente ist, dass Sie einen wirklich guten Polymorphismus erhalten: Alles, was eine Klasse tun muss, um Verhalten zu liefern, ist die Methode bereitzustellen. Solange alle nett spielen und nur Nachrichten senden, die den definierten Methoden entsprechen, ist alles in Ordnung. Der Nachteil ist, dass der unten stehende Fehler erst zur Laufzeit abgefangen wird:
Statisch typisierte Sprachen bieten eine viel bessere "vertragliche Programmierung", da sie beim Kompilieren die beiden folgenden Fehlerarten abfangen:
- -
Also ... um es zusammenzufassen:
Mit der Schnittstellenimplementierung können Sie angeben, welche Arten von Dingen Objekte ausführen können (Interaktion), und mit der Klassenvererbung können Sie festlegen, wie die Aufgaben ausgeführt werden sollen (Implementierung).
Schnittstellen bieten uns viele Vorteile des "echten" Polymorphismus, ohne die Überprüfung des Compilertyps zu beeinträchtigen.
quelle
Normalerweise definieren Schnittstellen die Schnittstelle, die Sie verwenden sollten (wie der Name schon sagt ;-)). Stichprobe
Jetzt
foo
akzeptiert Ihre FunktionArrayList
s,LinkedList
s, ... nicht nur einen Typ.Das Wichtigste in Java ist, dass Sie mehrere Schnittstellen implementieren können, aber nur EINE Klasse erweitern können! Stichprobe:
ist aber möglich ist nicht!Ihr obiger Code könnte auch sein :
IBox myBox = new Rectangle();
. Wichtig ist jetzt, dass myBox NUR die Methoden / Felder von IBox enthält und nicht die (möglicherweise vorhandenen) anderen Methoden von IBoxRectangle
.quelle
Ich denke, Sie verstehen alles, was Schnittstellen tun, aber Sie stellen sich noch nicht vor, in welchen Situationen eine Schnittstelle nützlich ist.
Wenn Sie ein Objekt innerhalb eines engen Bereichs (z. B. innerhalb eines Methodenaufrufs) instanziieren, verwenden und freigeben, fügt eine Schnittstelle nichts hinzu. Wie Sie bemerkt haben, ist die konkrete Klasse bekannt.
Schnittstellen sind nützlich, wenn ein Objekt an einer Stelle erstellt und an einen Aufrufer zurückgegeben werden muss, der sich möglicherweise nicht um die Implementierungsdetails kümmert. Lassen Sie uns Ihr IBox-Beispiel in eine Form ändern. Jetzt können wir Implementierungen von Shape wie Rectangle, Circle, Triangle usw. haben. Die Implementierungen der Methoden getArea () und getSize () sind für jede konkrete Klasse völlig unterschiedlich.
Jetzt können Sie eine Factory mit einer Vielzahl von createShape (params) -Methoden verwenden, die abhängig von den übergebenen Parametern eine geeignete Shape zurückgeben. Die Factory weiß natürlich, welche Art von Shape erstellt wird, der Aufrufer jedoch nicht sich darum zu kümmern, ob es sich um einen Kreis oder ein Quadrat handelt oder so weiter.
Stellen Sie sich nun vor, Sie haben eine Vielzahl von Operationen, die Sie an Ihren Formen ausführen müssen. Möglicherweise müssen Sie sie nach Bereichen sortieren, alle auf eine neue Größe einstellen und sie dann in einer Benutzeroberfläche anzeigen. Die Formen werden alle von der Fabrik erstellt und können dann sehr einfach an die Klassen Sorter, Sizer und Display übergeben werden. Wenn Sie in Zukunft eine Sechseckklasse hinzufügen müssen, müssen Sie nur die Fabrik ändern. Ohne die Benutzeroberfläche wird das Hinzufügen einer weiteren Form zu einem sehr unübersichtlichen Prozess.
quelle
du könntest es tun
Auf diese Weise verwenden Sie dieses Objekt als Ibox und es ist Ihnen egal, dass es wirklich ist
Rectangle
.quelle
Square
Sie ein Problem ... Wenn Sie versuchen, es ohne Schnittstellen zu tun, können Sie dies nicht garantierenSquare
undRectangle
haben die gleichen Methoden ... dies kann zu einem Albtraum führen, wenn Sie haben eine größere Codebasis ... Denken Sie daran, Schnittstellen definieren eine Vorlage.WARUM SCHNITTSTELLE ??????
Es beginnt mit einem Hund. Insbesondere ein Mops .
Der Mops hat verschiedene Verhaltensweisen:
Und Sie haben einen Labrador, der auch eine Reihe von Verhaltensweisen hat.
Wir können einige Möpse und Labore machen:
Und wir können uns auf ihr Verhalten berufen:
Nehmen wir an, ich betreibe einen Hundezwinger und muss alle Hunde, die ich unterbringe, im Auge behalten. Ich muss meine Möpse und Labradore in separaten Arrays aufbewahren :
Dies ist aber eindeutig nicht optimal. Wenn ich auch einige Pudel unterbringen möchte , muss ich meine Kennel-Definition ändern, um eine Reihe von Pudeln hinzuzufügen. Tatsächlich brauche ich für jede Art von Hund ein separates Array.
Einsicht: Sowohl Möpse als auch Labradore (und Pudel) sind Hundetypen und haben das gleiche Verhalten. Das heißt, wir können (für die Zwecke dieses Beispiels) sagen, dass alle Hunde bellen können, einen Namen haben und möglicherweise einen lockigen Schwanz haben oder nicht. Wir können eine Schnittstelle verwenden, um zu definieren, was alle Hunde tun können, aber es den spezifischen Hundetypen überlassen, diese bestimmten Verhaltensweisen zu implementieren. Die Benutzeroberfläche sagt "hier sind die Dinge, die alle Hunde tun können", sagt aber nicht, wie jedes Verhalten gemacht wird.
Dann ändere ich die Mops- und Laborklassen leicht, um das Hundeverhalten zu implementieren. Wir können sagen, dass ein Mops ein Hund und ein Labor ein Hund ist.
Ich kann Pugs and Labs immer noch wie zuvor instanziieren, aber jetzt bekomme ich auch einen neuen Weg, dies zu tun:
Dies besagt, dass d1 nicht nur ein Hund ist, sondern speziell ein Mops. Und d2 ist auch ein Hund, speziell ein Labor. Wir können die Verhaltensweisen aufrufen und sie funktionieren wie zuvor:
Hier zahlt sich die zusätzliche Arbeit aus. Die Kennel-Klasse wird viel einfacher. Ich benötige nur ein Array und eine addDog-Methode. Beide funktionieren mit jedem Objekt, das ein Hund ist. Das heißt, Objekte, die die Dog-Schnittstelle implementieren.
So verwenden Sie es:
Die letzte Aussage würde anzeigen: Spot Fido
Über eine Schnittstelle können Sie eine Reihe von Verhaltensweisen angeben, die alle Klassen, die die Schnittstelle implementieren, gemeinsam nutzen. Folglich können wir Variablen und Sammlungen (z. B. Arrays) definieren, die nicht im Voraus wissen müssen, welche Art von spezifischem Objekt sie enthalten, sondern nur Objekte, die die Schnittstelle implementieren.
quelle
Ein gutes Beispiel für die Verwendung von Schnittstellen ist das Collections-Framework. Wenn Sie eine Funktion schreiben, die a benötigt
List
, spielt es keine Rolle, ob der Benutzer eineVector
oder eineArrayList
oder eineHashList
oder was auch immer übergibt . Und Sie können dies auchList
an jede Funktion übergeben, die eineCollection
oder eineIterable
Schnittstelle benötigt.Dies macht Funktionen wie
Collections.sort(List list)
möglich möglich, unabhängig davon, wie dasList
implementiert ist.quelle
Dies ist der Grund, warum Factory Patterns und andere Kreationsmuster in Java so beliebt sind. Sie haben Recht, dass Java ohne sie keinen sofort einsatzbereiten Mechanismus für die einfache Abstraktion der Instanziierung bietet. Trotzdem erhalten Sie überall eine Abstraktion, wo Sie in Ihrer Methode kein Objekt erstellen, das den größten Teil Ihres Codes ausmachen sollte.
Abgesehen davon ermutige ich die Leute im Allgemeinen, den "IRealname" -Mechanismus zum Benennen von Schnittstellen nicht zu befolgen. Das ist eine Windows / COM-Sache, die einen Fuß in das Grab der ungarischen Notation setzt und wirklich nicht notwendig ist (Java ist bereits stark typisiert, und der springende Punkt bei Schnittstellen ist, dass sie so weit wie möglich nicht von Klassentypen zu unterscheiden sind).
quelle
Vergessen Sie nicht, dass Sie zu einem späteren Zeitpunkt eine vorhandene übernehmen können Klasse übernehmen und implementieren können
IBox
können. Sie wird dann für alle Ihre Box-fähigen Codes verfügbar.Dies wird etwas klarer, wenn die Schnittstellen den Namen -able haben . z.B
usw. (Namensschemata funktionieren nicht immer, zB bin ich mir nicht sicher, ob dies
Boxable
hier angemessen ist)quelle
Ich aktualisiere die Antwort mit neuen Funktionen der Benutzeroberfläche, die mit Java 8 eingeführt wurden Version eingeführt wurden.
Von der Oracle-Dokumentationsseite zur Zusammenfassung der Benutzeroberfläche :
Eine Schnittstellendeklaration kann enthalten
Die einzigen Methoden, die implementiert sind, sind Standardmethoden und statische Methoden.
Verwendung der Schnittstelle :
Serializable
Schnittstelle implementieren, eine Beziehung zwischen ihnen haben oder nicht, außer dass diese Schnittstelle implementiert wirdEinige verwandte SE-Fragen in Bezug auf den Unterschied zwischen abstrakter Klasse und Schnittstelle und Anwendungsfälle mit Arbeitsbeispielen:
Was ist der Unterschied zwischen einer Schnittstelle und einer abstrakten Klasse?
Wie hätte ich den Unterschied zwischen einer Interface- und einer Abstract-Klasse erklären sollen?
Schauen Sie sich die Dokumentationsseite an, um die neuen Funktionen von Java 8 zu verstehen: Standardmethoden und statische Methoden .
quelle
Der Zweck von Schnittstellen ist die Abstraktion oder Entkopplung von der Implementierung.
Wenn Sie eine Abstraktion in Ihr Programm einführen, interessieren Sie sich nicht für die möglichen Implementierungen. Sie interessieren sich dafür, was es kann und nicht wie , und Sie verwenden ein
interface
, um dies in Java auszudrücken.quelle
Wenn Sie über CardboardBox und HtmlBox verfügen (beide implementieren IBox), können Sie beide an jede Methode übergeben, die eine IBox akzeptiert. Auch wenn beide sehr unterschiedlich und nicht vollständig austauschbar sind, können Methoden, die sich nicht für "Öffnen" oder "Größenänderung" interessieren, Ihre Klassen dennoch verwenden (möglicherweise, weil sie sich dafür interessieren, wie viele Pixel benötigt werden, um etwas auf einem Bildschirm anzuzeigen).
quelle
Schnittstellen, bei denen Java eine Fetatur hinzugefügt wurde, um eine Mehrfachvererbung zu ermöglichen. Die Entwickler von Java erkannten jedoch, dass Mehrfachvererbung eine "gefährliche" Funktion war, weshalb sie auf die Idee einer Schnittstelle kamen.
Mehrfachvererbung ist gefährlich, da Sie möglicherweise eine Klasse wie die folgende haben:
Welches wäre die Methode, die aufgerufen werden sollte, wenn wir verwenden
Alle Probleme werden mit Schnittstellen gelöst, weil Sie wissen, dass Sie die Schnittstellen erweitern können und dass sie keine Klassifizierungsmethoden haben. Natürlich ist der Compiler nett und sagt Ihnen, wenn Sie keine Methoden implementiert haben, aber ich denke gerne, dass dies der Fall ist ein Nebeneffekt einer interessanteren Idee.
quelle
Hier ist mein Verständnis des Schnittstellenvorteils. Korrigieren Sie mich, wenn ich falsch liege. Stellen Sie sich vor, wir entwickeln ein Betriebssystem und ein anderes Team entwickelt die Treiber für einige Geräte. Deshalb haben wir eine Schnittstelle StorageDevice entwickelt. Wir haben zwei Implementierungen davon (FDD und HDD), die von anderen Entwicklerteams bereitgestellt werden.
Dann haben wir eine OperatingSystem-Klasse, die Schnittstellenmethoden wie saveData aufrufen kann, indem nur eine Instanz der Klasse übergeben wird, die die StorageDevice-Schnittstelle implementiert hat.
Der Vorteil hierbei ist, dass uns die Implementierung der Schnittstelle egal ist. Das andere Team erledigt die Aufgabe durch Implementierung der StorageDevice-Schnittstelle.
quelle