Interfaces in Java

Fragen zu allen anderen Programmiersprachen.
Angelo
Beiträge: 102
Registriert: 20.02.2010 14:47
Wohnort: Berlin

Interfaces in Java

Beitrag von Angelo »

Ich habe mal ein bisschen in Java hineingeschaut und bin nach kurzer Zeit auf ein erstes Hindernis gestoßen, nämlich auf Interfaces. Ich poste mein Problem hier im PB-Forum, weil ich in keinem Java-Forum angemeldet bin und weil ich, wie gesagt, nur mal in Java reinschnuppern will.

Hier also mein Problem: Ich habe eine Superklasse Tier und davon abgeleitet die Unterklassen Loewe und Katze, wobei Katze noch das Interface Haustier implementiert, das die abstrakte Methode streicheln() enthält. In meiner Startklasse erzeuge ich nun das polymorphe Array meineTierList[]. Der Compiler steigt in der Zeile meineTierListe[1].streicheln() aus. Mir ist klar, dass die Methode streicheln() nicht in der Klasse Tier enthalten ist. Aber ich dachte, das ist gerade der „Witz“ von Interfaces, dass man – bezogen auf mein Beispiel - Haustier-Methoden (also streicheln) auf eine Tier-Referenz (also meineTierListe) anwenden kann. Habe ich da irgendwo einen Syntax-Fehler gemacht oder den Dreh mit den Interfaces nicht verstanden?

Code: Alles auswählen

class Tier {
	public void toeneMachen() {
		System.out.println("diese Methode wird ueberschrieben");
	}
}

interface Haustier {
	public abstract void streicheln(); 
}

class Loewe extends Tier {
	public void toeneMachen() {
		System.out.println("Roaaar!");
	}
}

class Katze extends Tier implements Haustier {
	public void toeneMachen() {
		System.out.println("Miau!");
	}
	public void streicheln() {
		System.out.println("Ich lasse mich gerne streicheln");
	}
}

public class Start {
	public static void main (String[] args) {
		Tier[] meineTierListe = new Tier[2]; 
		meineTierListe[0] = new Loewe();
		meineTierListe[1] = new Katze();
		meineTierListe[0].toeneMachen();
		meineTierListe[1].toeneMachen();
		meineTierListe[1].streicheln();

	}
}
PB 5.50; Win 7
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Interfaces in Java

Beitrag von NicTheQuick »

Na das Problem ist doch eigentlich offensichtlich. Der Typ Tier hat keine Methode streicheln. Ein Element aus dem Array Tier könnte ja auch ein Löwe sein, den man laut deinem Klassenbaum eben nicht streicheln kann. Du müsstest zuerst mittels instanceOf herausfinden, ob meineTierListe[1] wirklich eine Katze ist. Dann kannst du das Element explizit zur Katze casten und dann auch erst streicheln aufrufen. Klar soweit?
Angelo
Beiträge: 102
Registriert: 20.02.2010 14:47
Wohnort: Berlin

Re: Interfaces in Java

Beitrag von Angelo »

DAnke für Deine schnelle Antwort. Mir ist schon bewusst, dass die Klasse Tier keine Methode streicheln() enthält. Wenn ich aber Methoden nur auf diejenige Referenz anwenden kann, wo sie auch definiert sind - in meinem Beispiel wäre das: streicheln() anwenden nur auf die Referenz Katze -, dann brauche ich doch keine Interfaces. Wo ist dann der Mehrwert der Interfaces? Die sollen mir doch angeblich Flexibilität verschaffen!
PB 5.50; Win 7
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Interfaces in Java

Beitrag von NicTheQuick »

Für ein Einmann-Projekt bringen dir Interfaces auch nicht wirklich was. Das ist eher für größere Teams gedacht. So kann man durch Interfaces schon alle Methoden festlegen, die gebraucht werden und seit der Planung des Projektes feststehen. Dann kann jeder Programmierer seinen Teil programmieren und jeder andere kann schon die Interfaces benutzen und die entsprechende Autovervollständigung nutzen.
So lernt man es jedenfalls an der Uni. In der Praxis werden Interfaces kaum bis gar nicht benutzt. Abstrakte Klassen sind wesentlich wichtiger um - wie du es gemacht hast - vom Groben ins Feine zu abstrahieren.
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: Interfaces in Java

Beitrag von Danilo »

Interfaces sind auch genauso gut für Einmann-Projekte. Sie geben an was eine Klasse
implementieren soll/muss und garantieren somit das diese Klasse ein bestimmtes Verhalten
zur Verfügung stellt.
Über abstrakte Klassen oder normale Vererbung baust Du einen Baum auf. Interfaces
dagegen kannst Du beliebigen Klassen hinzufügen und diese garantieren somit das sie
das Interface implementieren, ohne einen strukturierten Baum aufzubauen.

In Deinem Beispiel macht eine strukturierung mit einer abstrakten Klasse mehr Sinn.
Du hast die Grundklasse Tier und Löwe erbt davon. Dann machst Du eine abstrakte
Klasse Haustier und von dieser erben dann Hund, Katze, Meerschwein und was Du willst.

Auf alle von Haustier abgeleiteten Klassen kannst Du dann streicheln anwenden.
Die Eigenschaft, dass man Haustiere streicheln kann, wird somit vererbt werden.

Das sieht dann so aus:
Bild

Mit einem Interface kannst Du das auch erreichen, aber machst es gleich komplizierter:
Bild

Interfaces machen mehr Sinn wenn keine direkte Verbindung der Elemente zueinander
besteht. Zum Beispiel ein Interface IDurchzählen, das Du allen möglichen Klassen zuordnen
kannst die man durchzählen kann, ohne das diese eine weitere Gemeinsamkeit oder
Abhängigkeit miteinander/voneinander haben. Ein Array kannst Du durchzählen, eine
Linked List oder eine Schulklasse. Array, LinkedList und Schulklasse implementieren das
Interface und garantieren damit das man sie durchzählen kann. Sonst haben sie aber
nichts gemeinsam.

Da Hund und Katze aber Haustiere sind, macht es mehr Sinn da mit (abstrakten) Klassen
zu vererben. Es ergibt sich ja aus der Beziehung schon automatisch die Struktur das
Hund und Katze dem Haustier untergeordnet sind.

In der Praxis findest Du übrigens auch sehr oft Interfaces. Im .NET Framework zum Beispiel
IEnumerable, IEnumerator, IComparer usw.
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Angelo
Beiträge: 102
Registriert: 20.02.2010 14:47
Wohnort: Berlin

Re: Interfaces in Java

Beitrag von Angelo »

Danke NicTheQuick und Danilo für Eure Antworten. Ich denke, das von mir gewählte Beispiel hat einfach nicht die Komplexität, dass man die Vorteile eines interface erkennen kann. Es war nur so, dass mich in dem Buch "Java von Kopf bis Fuß" die Polymorphie und damit polymorphe Arrays sehr fasziniert haben. Allerdings ist in diesem Buch auch kein entsprechendes Beispiel zu finden. Ich werde also noch ein bisschen tiefer einsteigen müssen. @Danilo: Danke für Deine großartigen Diagramme. Besser kann man das in keinem Java-Lehrbuch finden. :)
PB 5.50; Win 7
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: Interfaces in Java

Beitrag von Danilo »

Angelo hat geschrieben:Ich denke, das von mir gewählte Beispiel hat einfach nicht die Komplexität,
dass man die Vorteile eines interface erkennen kann.
Der Vorteil von Interfaces gegenüber abstrakten Klassen ist ihre Unabhängigkeit.
Da wird nichts vererbt, keine Hierarchie und kein Abhängigkeitsbaum aufgebaut.

Ein Interface ist ein Vertrag/eine Garantie das ein Objekt die Methoden im Interface
bereitstellt.

Du machst zum Beispiel ein Interface IDurchzählen:

Code: Alles auswählen

Interface IDurchzählen
    Start()
    string Next()
    static string const Ende = "ENDE"
EndInterface
Jede Klasse die das implementiert garantiert folgendes Verhalten:
- Beim aufruf von Start() wird das durchzählen initialisiert, so dass es am Anfang beginnt
- Bei jedem Aufruf von Next() wird das nächste Mitglied der Durchzählung zurückgegeben (als string).
- Wenn alles durchgezählt wurde gibt Next() IDurchzählen.Ende zurück.

Das ist der Vertrag über das Verhalten.

Nun kannst Du anfangen Funktionen zu schreiben die schon IDurchzählen
verwenden, ohne das sie weiteres über die Klassen wissen, die dieses
Interface implementieren werden.

Du hast in Deinem Klassensystem zum Beispiel eine Listbox-Klasse
mit der Methode Add um ganze Objekte anzuzeigen.
Deine Methode machst Du dann so:

Code: Alles auswählen

class Listbox : Gadget  // erbt von Gadget
    [...]

    Methode Add(IDurchzählen obj)
        Define string s
        obj.Start()
        While ( s=obj.Next() != IDurchzählen.Ende )
            Füge s der Listbox hinzu
        Wend
    EndMethode

   [...]
EndClass
Deine Methode Listbox.Add() nimmt nun jedes beliebige Objekt entgegen
das IDurchzählen implementiert hat und listet das in der Listbox auf.
Dabei muss Deine Klasse nichts weiter über das Objekt wissen, außer das
es sich durchzählen lässt.
Somit ist es vollkommen unabhängig von irgendeiner Vererbungshierarchie etc.

Nun kann jeder Klassen schreiben die IDurchzählen implementieren.
Diese beliebigen Klassen, egal für was sie sonst da sind, kann man Deiner
Listbox hinzufügen.

Ich mache zum Beispiel eine Klasse 'Schulklasse' und implementiere
das Interface IDurchzählen. Das heißt ich muß die Methoden Start()
und Next() zur Verfügung stellen.
Ich schreibe Schulklasse.Next() so, daß alle Namen der Schüler
in der Klasse nacheinander zurückgegeben werden.

Nun kann ich Listbox.Add(meineSchulkasse) aufrufen und in der
Listbox erscheint nacheinander: "Peter", "Monique", "Sarah", "Rolf", ... "Gunnar"

Ich habe noch eine ganz andere Klasse: Telefonbuch
Das Telefonbuch hat nichts mit der Schulklasse gemeinsam, keine Vererbung oder so.
Aber ich kann auch IDurchzählen in Telefonbuch implementieren:
Telefonbuch.Next() gibt nacheinander jeden Eintrag im Telefonbuch als string
zurück, und am Ende eben IDurchzählen.Ende.
Und schon kann ich auch Objekte vom Typ Telefonbuch der Listbox hinzufügen:
Listbox.Add(privatesTelefonbuch) zeigt in der Listbox an:
"Miriam, 0160 / 666 666"
"Elisabeth, 0160 / 123 123"
"Mutti, 089 / 576 682 5"
"Peter, 0172 / 83 83 549"


Und so kannst Du und jeder andere Programmierer auf der Welt in weitere beliebige Klassen
das Interface IDurchzählen implementieren.
Unabhängig davon kannst Du auch weitere Methoden schreiben, die ein beliebiges, unbekanntes Objekt
entgegen nehmen, sobald es das Interface IDurchzählen implementiert.

Zum Beispiel fügst Du eine Write-Methode zu Deiner File-Klasse hinzu, die
auch ein Objekt nimmt das IDurchzählen implementiert hat:

Code: Alles auswählen

Class File
    [...]

    Methode Write(IDurchzählen obj)
        Define string s
        obj.Start()
        While ( s=obj.Next() != IDurchzählen.Ende )
            Schreibe s in das aktuell geöffnete File
        Wend
    EndMethode

   [...]
EndClass
Und schon kannst Du File.Write(meineSchulklasse) und auch
File.Write(privatesTelefonbuch) benutzen um es abzuspeichern.

Jede weitere Klasse, in die Du später auch das Interface IDurchzählen
implementierst, kannst Du danach mit Listbox.Add() und File.Write()
benutzen, ohne an Listbox oder File etwas ändern zu müssen.

Ist es so zu verstehen? :)
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Angelo
Beiträge: 102
Registriert: 20.02.2010 14:47
Wohnort: Berlin

Re: Interfaces in Java

Beitrag von Angelo »

@Danilo: Was kann ich sagen? Vielen Dank für Deine super ausführliche Antwort. Es ist toll, dass Du es so konkret gemacht hast. Wow! :) Ich muss mir wirklich die notwendige Zeit nehmen, mir das ganz genau anzuschauen. Ich bin sicher, dass ich zu Deinen Beispielen noch die eine oder andere Verständnisfrage haben werde. Aber zumindest wollte ich diese Rückmeldung schon mal geben!!!
PB 5.50; Win 7
Antworten