wake-up-neo.net

Gibt es mehr zu einer Schnittstelle als die richtigen Methoden

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 IBox-Schnittstelle verwenden wollte, kann ich keine Instanz davon erstellen.

public static void main(String args[])
{
    Ibox myBox=new Ibox();
}

recht? Also müsste ich das eigentlich machen:

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, über die richtigen Methoden verfügt, die von einer Schnittstelle beschrieben werden. Oder gibt es eine andere Verwendung von Schnittstellen?

159
Click Upvote

Schnittstellen sind eine Möglichkeit, Ihren Code flexibler zu gestalten. Was Sie tun, ist das:

Ibox myBox=new Rectangle();

Wenn Sie später entscheiden, eine andere Art von Box zu verwenden (möglicherweise gibt es eine andere Bibliothek mit einer besseren Art von Box), ändern Sie Ihren Code in:

Ibox myBox=new OtherKindOfBox();

Sobald Sie sich daran gewöhnt haben, werden Sie feststellen, dass dies eine großartige (eigentlich unverzichtbare) Arbeitsweise ist.

Ein weiterer Grund ist beispielsweise, dass Sie eine Liste von Feldern erstellen und einige Vorgänge für jedes Feld ausführen möchten, die Liste jedoch unterschiedliche Arten von Feldern enthalten soll. Auf jeder Box können Sie Folgendes tun:

myBox.close()

(unter der Annahme, dass IBox eine close () -Methode hat), obwohl sich die tatsächliche Klasse von myBox in Abhängigkeit davon ändert, an welcher Box Sie sich in der Iteration befinden.

143
morgancodes

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 die eine Stelle ändern müssen, an der sich das Objekt befindet geschaffen". Das ist kein Problem.

Der eigentliche Punkt ist bereits im Namen enthalten: Sie definieren eine Schnittstelle, die jeder implementieren kann, um den gesamten Code zu verwenden, der auf dieser Schnittstelle ausgeführt wird. Das beste Beispiel ist Java.util.Collections, Das alle Arten von nützlichen Methoden bereitstellt, die ausschließlich mit Schnittstellen arbeiten, wie z. B. sort() oder reverse() für List. Der Punkt hier ist, dass dieser Code jetzt zum Sortieren oder Umkehren jeder Klasse verwendet werden kann, die die List -Schnittstellen implementiert - nicht nur ArrayList und LinkedList, aber auch selbst geschriebene Klassen, die möglicherweise so implementiert sind, wie es sich die Leute, die Java.util.Collections geschrieben haben, 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 auffordern zu müssen, ihre Klassen zu unterstützen.

Eine andere häufige Verwendung von Schnittstellen ist für Rückrufe. Zum 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 JTable und irgendwann während des Renderns der Tabelle wird Ihr Code aufgerufen, um seine Aufgaben zu erledigen.

120

Eine der vielen Anwendungen, die ich gelesen habe, ist, wo es schwierig ist, ohne Schnittstellen mit Mehrfachvererbung in Java:

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

Stellen Sie sich nun einen Fall vor, in dem:

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

aber,

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

Besseres Design wäre:

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

Animal hat nicht die chew () -Methode und wird stattdessen wie folgt in eine Schnittstelle eingefügt:

interface Chewable {
void chew();
}

und lassen Sie die Reptile-Klasse dies implementieren und nicht Birds (da Birds nicht kauen können):

class Reptile extends Animal implements Chewable { } 

und bei Vögeln einfach:

class Bird extends Animal { }
118
peevesy

Der Zweck von Interfaces ist Polymorphismus, a.k.a. Typensubstitution. Zum Beispiel mit der folgenden Methode:

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

Beim Aufrufen der Methode scale können Sie einen beliebigen Wert eines Typs angeben, der die Schnittstelle IBox implementiert. Mit anderen Worten, wenn Rectangle und Square beide IBox implementieren, können Sie entweder Rectangle oder Square angeben, wo immer ein IBox wird erwartet.

46
Apocalisp

Mit Schnittstellen können statisch typisierte Sprachen den Polymorphismus unterstützen. Ein objektorientierter Purist würde darauf bestehen, dass eine Sprache Vererbung, Verkapselung, Modularität und Polymorphismus bietet, um eine voll funktionsfähige objektorientierte Sprache zu sein. In dynamisch getippten oder entengetippten Sprachen (wie Smalltalk) ist Polymorphismus trivial. In statisch typisierten Sprachen (wie Java oder C #)) ist der Polymorphismus jedoch alles andere als trivial (tatsächlich scheint er an der Oberfläche mit dem Begriff der starken Typisierung zu unvereinbar zu sein).

Lassen Sie mich demonstrieren:

In einer dynamisch getippten Sprache (wie Smalltalk) sind alle Variablen Verweise auf Objekte (nicht weniger und nicht mehr). In Smalltalk kann ich also Folgendes tun:

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

anAnimal := Cow new.
anAnimal makeNoise.

Dieser Code:

  1. Deklariert eine lokale Variable namens anAnimal (beachten Sie, dass wir NICHT den TYP der Variablen angeben - alle Variablen sind Verweise auf ein Objekt, nicht mehr und nicht weniger.)
  2. Erstellt eine neue Instanz der Klasse "Pig"
  3. Weist diese neue Instanz von Pig der Variablen anAnimal zu.
  4. Sendet die Nachricht makeNoise an das Schwein.
  5. Wiederholt das Ganze mit einer Kuh, weist es aber derselben exakten Variablen zu wie das Schwein.

Derselbe Java Code würde ungefähr so ​​aussehen (unter der Annahme, dass Duck und Cow Unterklassen von Animal sind:

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

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

Das ist alles schön und gut, bis wir Klasse Gemüse vorstellen. Gemüse hat ein ähnliches Verhalten wie Tier, aber nicht alle. Zum Beispiel können sowohl Tier 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:

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

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

Dies funktioniert in Smalltalk perfekt, 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. Wenn eine passende Methode gefunden wird, wird sie aufgerufen. Andernfalls wird eine Art NoSuchMethodError-Ausnahme ausgelöst, die jedoch zur Laufzeit ausgeführt wird.

Aber in Java, einer statisch typisierten Sprache, welchen Typ können wir unserer Variablen zuweisen? Mais muss von Gemüse geerbt werden, um das Wachstum zu unterstützen, kann jedoch nicht von Tier geerbt werden, da es keinen Lärm macht. Kuh muss von Animal erben, um makeNoise zu unterstützen, kann aber nicht von Vegetable erben, da es keine Ernte durchführen sollte. Es sieht so aus, als ob wir Mehrfachvererbung - die Fähigkeit benötigen, von mehr als einer Klasse zu erben. Aber das ist eine ziemlich schwierige Sprache, da alle Edge-Fälle auftauchen (was passiert, wenn mehr als eine parallele Superklasse dieselbe Methode implementiert? Usw.)

Mit dabei sind Schnittstellen ...

Wenn wir Tier- und Gemüseklassen mit jeder Implementierung von Growable erstellen, 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 zu vergrößern:

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

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

Und das können wir tun, um Tiergeräusche zu machen:

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

Der Vorteil der ententypisierten Sprache besteht darin, dass Sie einen wirklich netten Polymorphismus erhalten: Alles, was eine Klasse tun muss, um Verhalten bereitzustellen, ist, die Methode bereitzustellen. Solange alle Nice spielen und nur Nachrichten senden, die definierten Methoden entsprechen, ist alles in Ordnung. Der Nachteil ist, dass die Art des Fehlers unten erst zur Laufzeit abgefangen wird:

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

Statisch typisierte Sprachen bieten eine viel bessere "Programmierung nach Vertrag", da sie beim Kompilieren die folgenden zwei Arten von Fehlern erkennen:

// 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(); 

Also ... um zusammenzufassen:

  1. Mit der Schnittstellenimplementierung können Sie festlegen, welche Aufgaben Objekte ausführen können (Interaktion), und mit der Klassenvererbung können Sie festlegen, wie Aufgaben ausgeführt werden sollen (Implementierung).

  2. Schnittstellen bieten uns viele Vorteile des "wahren" Polymorphismus, ohne die Überprüfung des Compilertyps zu beeinträchtigen.

33
Jared

Normalerweise definieren Interfaces die zu verwendende Schnittstelle (wie der Name schon sagt ;-)). Probe


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

Jetzt akzeptiert Ihre Funktion fooArrayLists, LinkedLists, ... nicht nur einen Typ.

Das Wichtigste in Java ist, dass Sie mehrere Schnittstellen implementieren können, aber nur EINE Klasse erweitern können! Beispiel:


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

class Test extends Foo, Bar, Buz {
...
}

Ihr Code oben könnte auch sein: IBox myBox = new Rectangle();. Wichtig ist nun, dass myBox NUR die Methoden/Felder aus IBox enthält und nicht die (eventuell vorhandenen) anderen Methoden aus Rectangle.

9
Johannes Weiss

Ich denke, Sie verstehen alles, was Interfaces tun, aber Sie können sich noch nicht vorstellen, in welchen Situationen ein Interface nützlich ist.

Wenn Sie ein Objekt innerhalb eines engen Bereichs (z. B. innerhalb eines Methodenaufrufs) instantiieren, verwenden und freigeben, fügt ein Interface eigentlich nichts hinzu. Wie Sie bemerkt haben, ist die konkrete Klasse bekannt.

Schnittstellen sind nützlich, wenn ein Objekt an einem Ort erstellt und an einen Aufrufer zurückgegeben werden muss, dem die Implementierungsdetails möglicherweise nicht wichtig sind. 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, welcher Shape-Typ erstellt wird, der Aufrufer jedoch nicht sich darum zu kümmern, ob es ein Kreis oder ein Quadrat ist 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 Bereich sortieren, sie 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 Hexagon-Klasse hinzufügen müssen, müssen Sie nur die Factory ändern. Ohne die Benutzeroberfläche wird das Hinzufügen einer anderen Form zu einem sehr unübersichtlichen Vorgang.

6
Ickster

du könntest es tun

Ibox myBox = new Rectangle();

auf diese Weise verwenden Sie dieses Objekt als Ibox und es ist Ihnen egal, dass es wirklich Rectangle ist.

6
IAdapter

WARUM SCHNITTSTELLE ??????

Es beginnt mit einem Hund. Insbesondere ein Mops.

Der Mops hat verschiedene Verhaltensweisen:

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; } }

Und Sie haben einen Labrador, der auch eine Reihe von Verhaltensweisen hat.

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; } }

Wir können ein paar Möpse und Labore machen:

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

Und wir können ihr Verhalten aufrufen:

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

Nehmen wir an, ich führe eine Hundehütte und muss alle Hunde, die ich unterbringe, im Auge behalten. Ich muss meine Möpse und Labradore in getrennten Arrays aufbewahren:

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 } }

Dies ist aber eindeutig nicht optimal. Wenn ich möchte ein paar Pudel unterbringen muss ich auch meine Kenneldefinition ändern, um eine Reihe von Pudeln hinzuzufügen. Tatsächlich brauche ich für jede Hundeart ein eigenes Array.

Einsicht: Sowohl Möpse als auch Labradore (und Pudel) sind Arten von Hunden und weisen dasselbe Verhalten auf. 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 geschweiften Schwanz haben oder nicht. Wir können eine Schnittstelle verwenden, um zu definieren, was alle Hunde können, aber es den spezifischen Arten von Hunden überlassen, diese bestimmten Verhaltensweisen zu implementieren. Das Interface sagt "Hier sind die Dinge, die alle Hunde tun können", sagt aber nicht, wie jedes Verhalten getan wird.

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

Dann ändere ich leicht die Mops- und Laborklassen, um das Hundeverhalten zu implementieren. Wir können sagen, dass ein Mops ein Hund und ein Labor ein Hund ist.

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

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

Ich kann immer noch Pugs and Labs instanziieren, wie ich es zuvor getan habe, aber jetzt bekomme ich auch eine neue Möglichkeit, dies zu tun:

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

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:

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

Hier zahlt sich die ganze zusätzliche Arbeit aus. Die Zwingerklasse wird viel einfacher. Ich brauche nur ein Array und eine AddDog-Methode. Beide funktionieren mit jedem Objekt, das ein Hund ist. Objekte, die die Dog-Schnittstelle implementieren.

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

So verwenden Sie es:

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

Die letzte Anweisung würde anzeigen: Spot Fido

Mit einer Schnittstelle können Sie eine Reihe von Verhaltensweisen angeben, die alle Klassen, die die Schnittstelle implementieren, gemeinsam haben. Folglich können wir Variablen und Auflistungen definieren (wie z. B. Arrays), die nicht im Voraus wissen müssen, welche Art von spezifischem Objekt sie enthalten, sondern nur Objekte, die die Schnittstelle implementieren.

Dies ist der Grund, warum Factory Patterns und andere Kreationsmuster in Java so beliebt sind. Sie haben Recht, dass ohne sie Java keinen Standardmechanismus für die einfache Abstraktion der Instanziierung bietet. Trotzdem erhalten Sie Abstraktion überall dort, wo Sie anlegen 't erstellen Sie ein Objekt in Ihrer Methode, die den größten Teil Ihres Codes sein sollte.

Im Übrigen empfehle ich generell, den "IRealname" -Mechanismus zur Benennung 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 Sinn von Schnittstellen besteht darin, sie so weit wie möglich von Klassentypen zu unterscheiden).

3

Vergessen Sie nicht, dass Sie zu einem späteren Zeitpunkt eine vorhandene -Klasse verwenden und sie IBox implementieren lassen können. Sie wird dann für Ihren gesamten box-fähigen Code verfügbar.

Dies wird etwas deutlicher, wenn die Schnittstellen - able heißen. z.B.

public interface Saveable {
....

public interface Printable {
....

usw. (Benennungsschemata funktionieren nicht immer. Ich bin mir nicht sicher, ob Boxable hier angemessen ist.)

3
Brian Agnew

Ein gutes Beispiel für die Verwendung von Schnittstellen ist das Collections-Framework. Wenn Sie eine Funktion schreiben, die ein List annimmt, spielt es keine Rolle, ob der Benutzer ein Vector oder ein ArrayList oder ein HashList oder ein _ übergibt wie auch immer. Und Sie können dieses List an jede Funktion übergeben, die auch eine Collection - oder Iterable -Schnittstelle benötigt.

Dies ermöglicht Funktionen wie Collections.sort(List list), unabhängig davon, wie List implementiert ist.

3
Kip

der einzige Zweck von Schnittstellen besteht darin, sicherzustellen, dass die Klasse, die eine Schnittstelle implementiert, die richtigen Methoden enthält, die von einer Schnittstelle beschrieben werden. Oder gibt es eine andere Verwendung von Schnittstellen?

Ich aktualisiere die Antwort mit neuen Funktionen der Benutzeroberfläche, die mit Java 8 eingeführt wurden.

Von der Oracle-Dokumentationsseite aus Zusammenfassung der Benutzeroberfläche :

Eine Schnittstellendeklaration kann enthalten

  1. methodensignaturen
  2. standardmethoden
  3. statische Methoden
  4. konstante Definitionen.

Die einzigen Methoden, die implementiert sind, sind Standardmethoden und statische Methoden.

Verwendung der Schnittstelle :

  1. So definieren Sie einen Vertrag
  2. Das Verknüpfen von nicht verwandten Klassen mit verfügt über Funktionen (z. B. Klassen, die die Serializable -Schnittstelle implementieren, können eine Beziehung zwischen ihnen haben oder nicht, mit Ausnahme der Implementierung dieser Schnittstelle
  3. Bereitstellung einer austauschbaren Implementierung z. B. eines Strategiemusters
  4. Mit den Standardmethoden können Sie den Schnittstellen Ihrer Bibliotheken neue Funktionen hinzufügen und die Binärkompatibilität mit Code sicherstellen, der für ältere Versionen dieser Schnittstellen geschrieben wurde
  5. Organisieren Sie Hilfsmethoden in Ihren Bibliotheken mit statischen Methoden (Sie können statische Methoden, die für eine Schnittstelle spezifisch sind, in derselben Schnittstelle und nicht in einer separaten Klasse aufbewahren).

Einige verwandte SE-Fragen bezüglich des Unterschieds zwischen abstract class und interface und Anwendungsfällen 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 Seite Dokumentation an, um die neuen Funktionen zu verstehen, die in Java 8: Standardmethoden und statische Methoden hinzugefügt wurden.

3
Ravindra babu

Der Zweck von Schnittstellen ist Abstraktion oder die Entkopplung von der Implementierung.

Wenn Sie eine Abstraktion in Ihr Programm einfügen, interessieren Sie sich nicht für die möglichen Implementierungen. Sie interessieren sich für , was es kann und nicht wie und Sie Verwenden Sie ein interface, um dies in Java auszudrücken.

2
eljenso

Wenn Sie CardboardBox und HtmlBox haben (beide implementieren IBox), können Sie beide an jede Methode übergeben, die eine IBox akzeptiert. Obwohl beide sehr unterschiedlich und nicht vollständig austauschbar sind, können Methoden, die sich nicht für "Öffnen" oder "Ändern der Größe" interessieren, trotzdem Ihre Klassen verwenden (möglicherweise, weil sie sich darum kümmern, wie viele Pixel für die Anzeige von etwas auf einem Bildschirm benötigt werden).

1
Todd R

Schnittstellen, bei denen eine Fetatur zu Java) hinzugefügt wurde, um Mehrfachvererbung zu ermöglichen. Die Entwickler von Java=) haben jedoch erkannt, dass Mehrfachvererbung eine "gefährliche" Funktion ist warum der auf die idee einer schnittstelle kam.

mehrfachvererbung ist gefährlich, da Sie möglicherweise eine Klasse wie die folgende haben:


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
}

Welches wäre die Methode, die aufgerufen werden sollte, wenn wir verwenden


   FunckyFigure.GetArea(); 

Alle Probleme werden mit Interfaces gelöst, weil Sie wissen, dass Sie die Interfaces 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, das ist es gerne ein Nebeneffekt einer interessanteren Idee.

1
mandel

Hier ist mein Verständnis von Interface-Vorteil. Korrigiere 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 ein Interface StorageDevice entwickelt. Wir haben zwei Implementierungen davon (FDD und HDD), die von einem anderen Entwicklerteam bereitgestellt werden.

Dann haben wir eine OperatingSystem-Klasse, die Schnittstellenmethoden wie saveData aufrufen kann, indem nur eine Instanz einer Klasse übergeben wird, die die StorageDevice-Schnittstelle implementiert.

Der Vorteil hierbei ist, dass uns die Implementierung der Schnittstelle egal ist. Das andere Team erledigt die Aufgabe durch die Implementierung der StorageDevice-Schnittstelle.

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...");    
    }
}
0