From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001
From: Sven Eisenhauer
+Es wurde bereits erwähnt, dass es in Java keine Mehrfachvererbung
+von Klassen gibt. Die möglichen Schwierigkeiten beim Umgang mit
+mehrfacher Vererbung und die Einsicht, dass das Erben nichttrivialer
+Methoden aus mehr als einer Klasse in der Praxis selten zu realisieren
+ist, haben die Designer dazu veranlaßt, dieses Feature nicht
+zu implementieren. Andererseits sah man es als wünschenswert
+an, dass Klassen eine oder mehrere Schnittstellendefinitionen erben
+können, und hat mit den Interfaces ein Ersatzkonstrukt
+geschaffen, das dieses Feature bietet.
+
+
+
+
+
+Ein Interface ist eine besondere Form einer Klasse, die ausschließlich
+abstrakte Methoden und Konstanten enthält. Anstelle des Schlüsselwortes
+class
+wird ein Interface mit dem Bezeichner interface
+deklariert. Alle Methoden eines Interface sind implizit abstrakt und
+öffentlich. Neben Methoden kann ein Interface auch Konstanten
+enthalten, die Definition von Konstruktoren ist allerdings nicht erlaubt.
+
+
+Wir wollen uns ein einfaches Beispiel ansehen. Das folgende Listing
+definiert ein Interface Groesse,
+das die drei Methoden laenge,
+hoehe und breite
+enthält:
+
+
+
+
+
+
+ Titel
+ Inhalt
+ Suchen
+ Index
+ DOC
+ Handbuch der Java-Programmierung, 5. Auflage
+
+ <<
+ <
+ >
+ >>
+ API
+ Kapitel 9 - OOP III: Interfaces
+
+
+
+
+
+9.1 Grundlagen
+
+
+
+
+
+
+9.1.1 Definition eines Interface
+
+
+
+
+Listing 9.1: Definition eines Interface
+
+
+
+
+
+001 /* Groesse.java */
+002
+003 public interface Groesse
+004 {
+005 public int laenge();
+006 public int hoehe();
+007 public int breite();
+008 }
+
+
+Groesse.java
+
+Diese Definition ähnelt sehr einer abstrakten Klasse und dient +dazu, eine Schnittstelle für den Zugriff auf die räumliche +Ausdehnung eines Objekts festzulegen. Wir wollen uns an dieser +Stelle keine Gedanken über komplizierte Details wie zu verwendende +Maßeinheiten oder Objekte mit mehr oder weniger als drei Dimensionen +machen. + + + + +
+Durch das bloße Definieren eines Interface wird die gewünschte +Funktionalität aber noch nicht zur Verfügung gestellt, sondern +lediglich beschrieben. Soll diese von einer Klasse tatsächlich +realisiert werden, muss sie das Interface implementieren . +Dazu erweitert sie die class-Anweisung +um eine implements-Klausel, +hinter der der Name des zu implementierenden Interfaces angegeben +wird. Der Compiler sorgt dafür, dass alle im Interface geforderten +Methoden definitionsgemäß implementiert werden. Zusätzlich +»verleiht« er der Klasse einen neuen Datentyp, der - wie +wir noch sehen werden - ähnliche Eigenschaften wie eine echte +Klasse hat. + +
+Eine beispielhafte Implementierung des Interfaces Groesse +könnte etwa von der schon bekannten Auto-Klasse +vorgenommen werden: + + +
+
+
+
+001 /* Auto2.java */
+002
+003 public class Auto2
+004 implements Groesse
+005 {
+006 public String name;
+007 public int erstzulassung;
+008 public int leistung;
+009 public int laenge;
+010 public int hoehe;
+011 public int breite;
+012
+013 public int laenge()
+014 {
+015 return this.laenge;
+016 }
+017
+018 public int hoehe()
+019 {
+020 return this.hoehe;
+021 }
+022
+023 public int breite()
+024 {
+025 return this.breite;
+026 }
+027 }
+
+ |
++Auto2.java | +
+Wir haben die Klasse dazu um drei veränderliche Instanzmerkmale +erweitert, die es uns erlauben, die vom Interface geforderten Methoden +auf einfache Weise zu implementieren. Ebenso wie die Klasse Auto +könnte auch jede andere Klasse das Interface +implementieren und so Informationen über seine räumliche +Ausdehnung geben: + + +
+
+
+
+001 public class FussballPlatz
+002 implements Groesse
+003 {
+004 public int laenge()
+005 {
+006 return 105000;
+007 }
+008
+009 public int hoehe()
+010 {
+011 return 0;
+012 }
+013
+014 public int breite()
+015 {
+016 return 70000;
+017 }
+018 }
+
+ |
++FussballPlatz.java | +
+Hier geben die Interface-Methoden konstante Werte zurück (in +der Annahme, dass alle Fußballplätze gleich groß +sind). Ebenso gut ist es möglich, dass die Größe von +anderen Instanzmerkmalen abhängig ist und zur Implementierung +des Interfaces etwas mehr Aufwand getrieben werden muss: + + +
+
+
+
+001 /* PapierBlatt.java */
+002
+003 public class PapierBlatt
+004 implements Groesse
+005 {
+006 public int format; //0=DIN A0, 1=DIN A1 usw.
+007
+008 public int laenge()
+009 {
+010 int ret = 0;
+011 if (format == 0) {
+012 ret = 1189;
+013 } else if (format == 1) {
+014 ret = 841;
+015 } else if (format == 2) {
+016 ret = 594;
+017 } else if (format == 3) {
+018 ret = 420;
+019 } else if (format == 4) {
+020 ret = 297;
+021 }
+022 //usw...
+023 return ret;
+024 }
+025
+026 public int hoehe()
+027 {
+028 return 0;
+029 }
+030
+031 public int breite()
+032 {
+033 int ret = 0;
+034 if (format == 0) {
+035 ret = 841;
+036 } else if (format == 1) {
+037 ret = 594;
+038 } else if (format == 2) {
+039 ret = 420;
+040 } else if (format == 3) {
+041 ret = 297;
+042 } else if (format == 4) {
+043 ret = 210;
+044 }
+045 //usw...
+046 return ret;
+047 }
+048 }
+
+ |
++PapierBlatt.java | +
+
![]() |
+
+
+ +Die Art der Realisierung der vereinbarten Methoden spielt für +das Implementieren eines Interface keine Rolle. Tatsächlich kommt +es ausgesprochen häufig vor, dass Interfaces von sehr unterschiedlichen +Klassen implementiert und die erforderlichen Methoden auf sehr unterschiedliche +Weise realisiert werden. |
+
+
|
+![]() |
+
+
![]() |
+![]() |
+
+
+ +Eine Klasse kann ein Interface auch dann implementieren, wenn sie +nicht alle seine Methoden implementiert. In diesem Fall ist die Klasse +allerdings als abstract +zu deklarieren und kann nicht dazu verwendet werden, Objekte zu instanzieren. |
+
+
|
+![]() |
+
+Nützlich ist ein Interface immer dann, wenn Eigenschaften +einer Klasse beschrieben werden sollen, die nicht direkt in seiner +normalen Vererbungshierarchie abgebildet werden können. Hätten +wir beispielsweise Groesse als +abstrakte Klasse definiert, ergäbe sich eine sehr unnatürliche +Ableitungshierarchie, wenn Autos, Fußballplätze und Papierblätter +daraus abgeleitet wären. Durch Implementieren des Groesse-Interfaces +können sie die Verfügbarkeit der drei Methoden laenge, +hoehe und breite +dagegen unabhängig von ihrer eigenen Vererbungslinie garantieren. + +
+Wir wollen uns ein einfaches Beispiel für die Anwendung des Interfaces +ansehen. Dazu soll eine Methode grundflaeche +entwickelt werden, die zu jedem Objekt, das das Interface Groesse +implementiert, dessen Grundfläche (Länge mal Breite) berechnet: + + +
+
+
+
+001 /* Listing0905.java */
+002
+003 public class Listing0905
+004 {
+005 public static long grundflaeche(Groesse g)
+006 {
+007 return (long)g.laenge() * g.breite();
+008 }
+009
+010 public static void main(String[] args)
+011 {
+012 //Zuerst erzeugen wir ein Auto2...
+013 Auto2 auto = new Auto2();
+014 auto.laenge = 4235;
+015 auto.hoehe = 1650;
+016 auto.breite = 1820;
+017 //Nun ein DIN A4-Blatt...
+018 PapierBlatt blatt = new PapierBlatt();
+019 blatt.format = 4;
+020 //Und zum Schluß einen Fußballplatz...
+021 FussballPlatz platz = new FussballPlatz();
+022 //Nun werden sie ausgegeben
+023 System.out.println("Auto: " + grundflaeche(auto));
+024 System.out.println("Blatt: " + grundflaeche(blatt));
+025 System.out.println("Platz: " + grundflaeche(platz));
+026 }
+027 }
+
+ |
++Listing0905.java | +
+Das Programm erzeugt zunächst einige Objekte, die das Groesse-Interface +implementieren. Anschließend werden sie an die Methode grundflaeche +übergeben, deren Argument g +vom Typ Groesse ist. Durch diese +Typisierung kann der Compiler sicherstellen, dass nur Objekte »des +Typs« Groesse an grundflaeche +übergeben werden. Das ist genau dann der Fall, wenn das übergebene +Objekt dieses Interface implementiert. + +
+Die Ausgabe des Programms ist:
+
+
+Auto: 7707700
+Blatt: 62370
+Platz: 7350000000
+
+
+
+
+An diesem Beispiel kann man bereits die wichtigste Gemeinsamkeit zwischen +abstrakten Klassen und Interfaces erkennen: Beide können im Programm +zur Deklaration von lokalen Variablen, Membervariablen oder Methodenparametern +verwendet werden. Eine Interface-Variable ist kompatibel zu allen +Objekten, deren Klassen dieses Interface implementieren. + +
+Auch der instanceof-Operator +kann auf Interfacenamen angewendet werden. Eine alternative Implementierung +der Methode grundflaeche, die +mit allen Objekttypen funktioniert, könnte dann etwa so aussehen: + + +
+
+
+
+001 public static long grundflaeche(Object o)
+002 {
+003 long ret = 0;
+004 if (o instanceof Groesse) {
+005 Groesse g = (Groesse)o;
+006 ret = (long)g.laenge() * g.breite();
+007 }
+008 return ret;
+009 }
+
+ |
+
+Diese Implementierung verhält sich für alle Objekte, die +das Interface Groesse implementieren, +so wie die vorige. Für alle übrigen Objekte wird 0 zurückgegeben. +
| Titel + | Inhalt + | Suchen + | Index + | DOC + | Handbuch der Java-Programmierung, 5. Auflage, Addison +Wesley, Version 5.0.1 + |
| << + | < + | > + | >> + | API + | © 1998, 2007 Guido Krüger & Thomas +Stark, http://www.javabuch.de + |