Programmieren in Java: Einführung


Kapitel 6: Klassen


Inhaltsverzeichnis

Dieses Buch ist unter einer Creative Commons-Lizenz lizensiert.


6.1 Allgemeines

Kapselung und Wiederverwendung

Sie haben bereits in vielen Beispielen mit Klassen gearbeitet und kennen den Unterschied zwischen Klassen und Objekten. Dennoch soll in einem eigenen Kapitel nochmal speziell auf Klassen eingegangen werden, nachdem Java ausschließlich auf Klassen basiert.

Die Verwendung von Klassen bietet mehrere Vorteile. Mit Hilfe geeigneter Zugriffsattribute lassen sich Daten verpacken und schützen. Man spricht von Kapselung. Die ideale Klasse sieht so aus, dass von anderen Klassen ausschließlich auf Methoden zugegriffen werden darf. Alle Eigenschaften - also Instanz- und Klassenvariablen - sind privat und können von außen nicht geändert werden.

Die Kapselung folgt einem Grundsatz, den Sie bereits kennengelernt haben: Der Gültigkeitsbereich von Variablen muss so weit wie möglich eingeschränkt werden. Klassen sind das ideale Instrument, um diesen Grundsatz in Programmen umzusetzen: Wenn eine Klasse nur private Eigenschaften besitzt, können nur Methoden der Klasse selber Eigenschaften verändern. Treten in einem Programm Fehler auf, weil irgendwelche Eigenschaften einer Klasse plötzlich falsche Werte enthalten, so müssen im Idealfall nur die Methoden der Klasse nach dem Fehler durchsucht werden - sie sind schließlich die einzigen, die auf die Eigenschaften zugreifen dürfen.

Neben Kapselung unterstützen Klassen durch die Vererbung ein Konzept, das Wiederverwendung genannt wird. Wiederverwendung bedeutet, dass in einem Programm auf Code zurückgegriffen werden kann, der bereits anderweitig geschrieben wurde. Das Konzept der Wiederverwendung spart nicht nur Arbeit, sondern beugt auch Fehlern vor. Anstatt dass jeder Programmierer den gleichen Code für sich neu entwickelt, greifen alle auf den gleichen Code zu. Das bedeutet, jeder Programmierer kann sich wirklich auf neue Aufgaben konzentrieren und verläßt sich darauf, dass der wiederverwendete Code korrekt arbeitet.

Die Wiederverwendung von Code ist heutzutage enorm bedeutend: Nicht nur Programmiersprachen unterstützen Wiederverwendung von Quellcode durch Vererbung, Microsoft und Sun Microsystems bieten mit ActiveX und JavaBeans eine erfolgreiche Möglichkeit der Wiederverwendung von kompiliertem Code an. Der strategische Ansatz der .NET-Philosophie von Microsoft basiert auf freien Zugriff auf jeden Code, völlig egal, in welcher Programmiersprache der Code geschrieben ist.


6.2 Definition

Klassen anlegen

Der grundsätzliche Aufbau einer Klassendefinition in Java sieht wie folgt aus.

class MyClass 
{ 
} 

Um eine Klasse zu definieren, müssen Sie auf alle Fälle das Schlüsselwort class angeben und dahinter einen Namen für die Klasse. Auf alle Fälle müssen Sie auch zwei geschweifte Klammern angeben, die eine mögliche Klassendefinition enthalten. Sie sind nicht gezwungen, Anweisungen zwischen die geschweiften Klammern zu stellen - dann ist die Klasse eben erstmal leer und besitzt keine Merkmale.

public class MyClass 
{ 
} 

Vor dem Schlüsselwort class kann ein public angegeben werden. Die Bedeutung von public im Zusammenhang mit class haben Sie bereits kennengelernt: Ohne public ist die Klasse lediglich im aktuellen Paket bekannt und kann nicht von Klassen außerhalb des Pakets verwendet werden. Ist die Klasse mit public definiert, kann jede beliebige Klasse auf sie zugreifen und beispielsweise Objekte vom Typ dieser Klasse erstellen.

Vor class kann außerdem das Schlüsselwort abstract angegeben werden. Eine Klasse ist dann abstrakt, wenn sie mindestens eine abstrakte Methode enthält. Eine abstrakte Methode ist eine Methode, die deklariert, aber nicht definiert ist. Betrachten Sie folgendes Beispiel.

public abstract class MyAbstract 
{ 
  public int x; 

  public void y() { } 
  public abstract void a(); 
} 

Die Klasse MyAbstract besitzt eine Eigenschaft x und die zwei Methoden y() und a(). Während die Variable x und die Methode y() auf die bekannte Weise definiert sind, besitzt die Methode a() keinen Methodenrumpf: Direkt hinter der geschlossenen runden Klammer der Parameterliste von a() ist ein Semikolon gesetzt. Damit sich der Compiler nicht über die Methode a() beschwert, muss sie mit dem Schlüsselwort abstract deklariert werden. Ist mindestens eine Methode einer Klasse mit abstract deklariert, so muss die gesamte Klasse mit abstract definiert werden. Aus diesem Grund steht das Schlüsselwort abstract nun auch vor class.

Die Methode a() ist zwar nun deklariert, aber nicht definiert. Was soll eigentlich passieren, wenn ein Objekt der Klasse MyAbstract mit new erstellt wird und dann über die Referenzvariable die Methode a() aufgerufen wird?

Nachdem die Methode a() nicht definiert ist, darf sie auch nicht aufgerufen werden. Damit sie nicht aufgerufen werden kann, dürfen auch keine Objekte vom Typ der Klasse MyAbstract erstellt werden. Und genau das verhindert das Schlüsselwort abstract vor class. Es ist nicht möglich, Objekte vom Typ einer abstrakten Klasse zu erstellen.

Es stellt sich die Frage, welchen Sinn eine Klasse hat, von der keine Objekte erstellt werden dürfen. Betrachten Sie nun folgendes Code-Beispiel.

public class MyChild extends MyAbstract 
{ 
  public void a() { } 
} 

Die Klasse MyChild wird von der Klasse MyAbstract abgeleitet, ist also eine Kindklasse von MyAbstract. Als Kindklasse bekommt sie alle Merkmale der Elternklasse vererbt, die mit den Zugriffsattributen public oder protected definiert sind. Liegt die Kindklasse im selben Paket wie die Elternklasse, werden außerdem mit package definierte Merkmale weitergegeben. In unserem Beispiel erhält die Klasse MyChild alle Merkmale von MyAbstract, nachdem sowohl die Eigenschaft als auch die beiden Methoden mit public definiert sind.

Die Klasse MyChild macht nun folgendes: Sie übernimmt die abstrakte Methode a() und definiert für sie einen vollständigen Methodenrumpf. Der ist zwar wie unschwer zu sehen leer, aber er ist angegeben - die geschweiften Klammern stehen hinter a(). Damit ist die abstrakte Methode a() definiert. Weil es keine anderen abstrakten Methoden in MyChild gibt, handelt es sich nicht mehr um eine abstrakte Klasse. Es können demnach Objekte vom Typ der Klasse MyChild erstellt werden.

Sinn und Zweck von abstrakten Klassen ist es, eine Klassenschnittstelle fest vorzugeben. Klassen, die von der abstrakten Klasse abgeleitet werden, bekommen teilweise definierte Eigenschaften und Methoden übergeben, werden aber gezwungen, ihrerseits die abstrakten Methoden zu definieren. Meistens werden abstrakte Methoden verwendet, weil die direkte Implementierung der Methode vollständig von der Kindklasse abhängt und es daher nicht möglich ist, in der Elternklasse diese Methode bereits zu definieren.

Abstrakte Klassen werden von Ihnen wahrscheinlich in den seltensten Fällen erstellt werden. Sie finden eher Verwendung beim Erstellen von Klassenhierarchien. Dennoch sollten Sie von abstrakten Klassen gehört haben, so dass Sie verstehen, um was es sich hierbei handelt, wenn Sie es in Ihren Java-Projekten auf einmal mit abstrakten Klassen zu tun bekommen.

public final class MyClass 
{ 
} 

Das Schlüsselwort final, mit dem Klassen definiert werden können, ist recht einfach zu verstehen: Eine als final definierte Klasse kann keine Kindklassen haben. Es ist nicht möglich, ein Klasse von einer final-Klasse abzuleiten.

Eine Klasse als final zu definieren erfolgt normalerweise aus Sicherheitsgründen oder aufgrund des Designs der Klasse. Die Klasse wird beispielsweise als so perfekt betrachtet, dass es keinen Grund zu geben scheint, von dieser Klasse eine Kindklasse zu erstellen und diese weiter zu perfektionieren.

Eine Klasse, die Sie in fast jedem Java-Programm benötigen und die als final definiert ist, ist java.lang.String. Von dieser Klasse können Sie keine Kindklassen ableiten - der Compiler würde sich sofort beschweren. Das Java-System erlaubt die Ableitung von java.lang.String aus Sicherheitsgründen nicht. Diese Klasse ist so wichtig, dass es nur eine einzige String-Klasse geben darf und keine abgewandelten Kinder.

Das Schlüsselwort final kann auch im Zusammenhang mit Methoden-Definitionen verwendet werden. Die genaue Bedeutung lernen Sie noch nachfolgend in diesem Kapitel kennen.

Die Schlüsselwörter extends und implements, die ebenfalls im Zusammenhang mit Klassendefinitionen angegeben werden können, werden nachfolgend in eigenen Abschnitten in diesem Kapitel besprochen.


6.3 Vererbung

Kindklassen erstellen und Methoden überschreiben

Wie man Vererbung einsetzt und Kindklassen erstellt, haben Sie bereits selber oft genug gemacht. Jedes Java-Applet besteht schließlich aus einer Klasse, die von java.applet.Applet abgeleitet werden muss. Die Vererbung erfolgt hierbei wie Sie ebenfalls bereits wissen über das Schlüsselwort extends, das hinter dem Klassennamen angegeben wird. Hinter extends wird wiederum die Klasse angegeben, von der abgeleitet werden soll.

public class MyApplet extends java.applet.Applet 
{ 
} 

Oben sehen Sie nochmal den grundsätzlichen Aufbau einer derartigen Vererbung für eine Klasse, die als Java-Applet im Browser eingesetzt werden soll.

Sie wissen ebenfalls bereits aus Kapitel 2, Java-Programme, dass es eine Reihe spezieller Methoden gibt, die in bestimmten Situationen automatisch für ein Java-Applet aufgerufen werden. So führt der Browser beispielsweise die Methode init() aus, wenn er zum ersten Mal ein Java-Applet lädt. Diese Methode ist in der Klasse java.applet.Applet definiert, und zwar mit einem leeren Methodenrumpf. Zwischen den geschweiften Klammern der Methode init() in der Klasse java.applet.Applet steht also nichts.

Wenn Sie nun in Ihrer Klasse, die von java.applet.Applet abgeleitet wird, eine Methode init() definieren, dann spricht man davon, dass Sie die geerbte Methode init() überschreiben. Sie definieren also die Methode init() nochmal neu, obwohl Sie diese Methode ja eigentlich von Ihrer Elternklasse geerbt haben.

Das Überschreiben von Methoden ist ein wichtiges Konzept in der Objektorientierung. Es ermöglicht, dass eine Kindklasse Methoden anpasst und sie für die Anwendung in der Kindklasse konkretisiert. Genau das machen Sie auch, wenn Sie eine Methode init() in Ihrer Klasse definieren: Sie möchten ja, dass beim Ladevorgang des Applets durch den Browser eine bestimmte Initialisierung ausgeführt wird. Wenn nicht, hätten Sie die Methode init() ja nicht extra angeben brauchen - sie wird von java.applet.Applet ja als leere Methode geerbt.

Auch die Methoden start(), stop(), destroy() und paint() - genaugenommen jede Methode, die an Ihre Klasse von java.applet.Applet vererbt wird - können Sie überschreiben und anpassen. Nichts anderes haben Sie bisher in fast allen Beispielen getan.

Wenn sich der Compiler beschwert, eine Methode zu kompilieren, die Sie zu überschreiben versucht haben, dann kann es daran liegen, dass die Methode in der Elternklasse mit dem Schlüsselwort final definiert wurde. Dieses Schlüsselwort wird einfach vor den Datentyp des Rückgabewertes einer Methode gestellt und bedeutet, dass in einer abgeleiteten Klasse diese Methode auf keinen Fall überschrieben werden darf. Normalerweise werden Methoden mit final definiert, wenn die Methode in der Klasse so wichtig ist, dass ihre Arbeitsweise nicht geändert werden darf - auch nicht in Kindklassen.

Der Unterschied zum Schlüsselwort final vor einer Klassendefinition ist, dass hier das Ableiten einer Kindklasse verboten ist. Das Schlüsselwort final vor einer Methodendefinition bedeutet, dass Kindklassen abgeleitet werden dürfen, dass aber diese spezielle mit final definierte Methode in der Kindklasse nicht überschrieben werden darf.

Wenn Sie eine Methode in Ihrer Klasse überschrieben haben, die von der Elternklasse geerbt wurde, liegen genaugenommen in Ihrer Klasse zwei Methoden vor, die den gleichen Namen und die gleiche Parameterliste haben: Die Methode, die geerbt wurde, und die Methode, die von Ihnen in der Klasse definiert wurde. Normalerweise wird nun immer die von Ihnen definierte Methode aufgerufen - das ist ja der Sinn der Überschreibung. Wenn Sie jedoch auf die Methode zugreifen müssen, die geerbt und von Ihnen überschrieben wurde, dann ist das trotzdem möglich.

public class MyApplet extends java.applet.Applet 
{ 
  void init() 
  { 
    super.init(); 
  } 
} 

Mit dem Schlüsselwort super können Sie auf die Elternklasse zugreifen. Es handelt sich hierbei um einen Mechanismus, um auf überschriebene Methoden der Elternklasse zugreifen zu können. Sie geben hierfür das Schlüsselwort super an, dann den Zugriffsoperator ., dann die Methode, die Sie aufrufen möchten.

Im obigen zugegebenermaßen recht sinnlosen Beispiel wird die Methode init() von der Klasse MyApplet überschrieben. Innerhalb der Methode erfolgt jedoch lediglich ein Aufruf der ursprünglichen init()-Methode, die von der Klasse java.applet.Applet geerbt wurde. Auf diese ursprüngliche Methode init() wird über das Schlüsselwort super zugegriffen.

Wenn Sie im obigen Beispiel das Schlüsselwort super nicht angeben, würden Sie die Methode init() in Ihrer Klasse aufrufen. Die Methode init() würde sich demnach immer wieder selbst aufrufen. Dies hat unvorhersehbare Auswirkungen und könnte zum Absturz des Programms führen.


6.4 Interfaces

Interfaces sind keine abstrakten Klassen

Interfaces sind ein merkwürdiges Gebilde, das in gewisser Weise an Klassen erinnert. So wie Klassen handelt es sich auch bei Interfaces um Datentypen. Im Folgenden sehen Sie einen Beispiel-Code für ein Interface.

public interface MyInterface 
{ 
} 

Das Interface wird ähnlich wie eine Klasse definiert: Es wird lediglich nicht das Schlüsselwort class angegeben, sondern das Schlüsselwort interface. Auch können Interfaces wie Klassen in Pakete gesteckt werden. Die offizielle Java-Klassenhierarchie definiert eine Reihe von Interfaces, die alle in bestimmten Paketen liegen und genau wie Klassen jeweils über den vollständigen Paketnamen angesprochen werden müssen.

Was ist nun der Unterschied zwischen einer Klasse und einem Interface? Die Definition eines Interfaces darf ausschließlich aus Eigenschaften und Methoden-Deklarationen bestehen. Eigenschaften werden hierbei automatisch auf einen konstanten Wert gesetzt. Methoden müssen und dürfen nicht mit dem Schlüsselwort abstract definiert werden, sind aber grundsätzlich immer abstrakt - es darf sich nur um Methoden-Deklarationen handeln, nicht um Methoden-Definitionen. Keine einzige in einem Interface angegebene Methode darf einen Methodenrumpf besitzen.

Wir erweitern obiges Beispiel daher um eine Eigenschaft und eine Methoden-Deklaration, so dass das Interface den Regeln in Java entspricht.

public interface MyInterface 
{ 
  public int Property = 10; 

  public void Method(); 
} 

Das Interface enthält nun eine Variable namens Property vom Typ int, die auf den Wert 10 gesetzt ist. Der Wert der Variablen kann nicht geändert werden, sie ist konstant. Außerdem ist im Interface eine Methode Method() deklariert, der - wie es sich gehört - kein Methodenrumpf folgt. Wir haben also eine gültige Interface-Definition vor uns. Was läßt sich mit der nun anfangen?

import java.applet.*; 

public class MyApplet extends Applet implements MyInterface 
{ 
  public void init() 
  { 
    int x = Property; 
  } 

  public void Method() { } 
} 

Nun kommt ein neues Schlüsselwort namens implements ins Spiel. Dieses wird hinter dem Klassenamen oder - wenn Vererbung verwendet wird - hinter dem Klassennamen der Elternklasse angegeben. Hinter diesem werden dann die Interfaces aufgelistet, die die Klasse implementiert. Mehrere Interfaces werden einfach durch Kommata getrennt.

Dies ist bereits ein enorm wichtiger Unterschied zu Klassen. Jede Klasse kann nur eine Elternklasse besitzen. Interfaces können jedoch beliebig viele implementiert werden.

Was bedeutet nun dieses Schlüsselwort implements genau? Es besagt, dass die in einem Interface definierten Eigenschaften geerbt werden und innerhalb der Klasse zur Verfügung stehen. Und es besagt, dass die Klasse alle jene Methoden definiert, die im Interface deklariert sind.

In unserem Beispiel bedeutet das, dass nun innerhalb der Klasse MyApplet auf eine Eigenschaft Property zugegriffen werden darf und diese im Programm verwendet werden kann - mit der Einschränkung, dass diese Eigenschaft konstant ist. Es ist nicht möglich, der Eigenschaft Property einen neuen Wert zuzuweisen.

Außerdem sind wir nun gezwungen, alle die Methoden in der Klasse MyApplet zu definieren, die im Interface MyInterface deklariert worden sind. Das ist im Beispiel nur die Methode Method() gewesen. Deswegen müssen wir nun diese Methode mit Methodenrumpf in der Klasse MyApplet angeben.

Java führt aus zwei Gründen Interfaces ein: Zum einen sind Interfaces die einzige Möglichkeit, Merkmale von unterschiedlichen Eltern zu erben, nachdem die Vererbung über Klassen nur maximal eine Elternklasse erlaubt. Diese Vererbung ist natürlich sehr beschränkt, da ja keine vollständigen Methoden vererbt werden können, sondern nur Deklarationen, und geerbte Eigenschaften immer konstant sind.

Zum anderen sind Interfaces nicht in eine bestimmte Hierarchie von Klassen eingeordnet, sondern stehen völlig frei im Raum. Das bedeutet, eine Klasse kann ein Interface implementieren unabhängig davon, ob es sich um ein Applet handelt oder um eine beliebige andere Klasse. Auf Interfaces kann jede Klasse zugreifen, ohne sich darum kümmern zu müssen, an einer bestimmten Position in einer Klassenhierarchie zu stehen.

Nachdem ein Interface nur Methoden deklariert und damit einer anderen Klasse vorschreibt, welche Methoden zu definieren sind, wird mit Interfaces ein bestimmtes Verhalten einer Klasse erzwungen. Indem das Interface Methoden deklariert, ist klar, dass diese Methoden für einen Aufruf in der Klasse zur Verfügung stehen. Ein Interface stellt also sicher, dass die entsprechende Klasse tatsächlich die im Interface deklarierten Methoden anbietet.

Dieses Vorschreiben von Methoden-Definitionen wird in Java in verschiedenen Situationen benötigt. Wenn beispielsweise eine Klasse auf Mausklicks reagieren soll, dann muss sie ein Interface namens java.awt.event.MouseListener implementieren. Dieses Interface schreibt vor, dass eine Reihe von Methoden in der Klasse definiert werden, die benötigt werden, um auf Mausklicks reagieren zu können. Jede beliebige Klasse, die das Interface java.awt.event.MouseListener implementiert, kann dann als Empfänger verwendet werden, um Mausklicks vom Java-System an die Anwendung weiterzuleiten und dort entsprechend zu reagieren.

import java.applet.*; 
import java.awt.*; 
import java.awt.event.*; 

public class MyApplet extends Applet implements MouseListener 
{ 
  public void init() 
  { 
    addMouseListener(this); 
  } 

  public void mouseReleased(MouseEvent ev) 
  { 
    setBackground(Color.blue); 
  } 

  public void mousePressed(MouseEvent ev) { } 
  public void mouseEntered(MouseEvent ev) { } 
  public void mouseExited(MouseEvent ev) { } 
  public void mouseClicked(MouseEvent ev) { } 
} 

Obiges Beispiel implementiert die fünf Methoden, die das Interface java.awt.event.MouseListener vorschreibt. Diese Methoden werden in bestimmten Situationen aufgerufen, wenn der Anwender mit der Maus klickt Es handelt sich also um typische Event-Handler. Damit die Methoden aufgerufen werden, wenn der Anwender mit der Maus auf das Java-Applet klickt, muss für das Java-Applet die Methode addMouseListener() aufgerufen werden. Dieser Methode wird als einziger Parameter eine Referenzvariable übergeben, die auf das Objekt verweist, in dem die fünf Methoden aus dem Interface java.awt.event.MouseListener definiert sind.

Das Schlüsselwort this ist eine Referenzvariable, die als Eigenschaft in jedem Objekt in Java automatisch zur Verfügung steht und die immer auf das eigene Objekt verweist, dessen Bestandteil sie ist. Indem also this als Parameter an die Methode addMouseListener() übergeben wird, sagen Sie dem Java-System, dass Mausklicks des Anwenders an das aktuelle Objekt weitergemeldet werden sollen - also das Objekt, das auf der Klasse MyApplet basiert und automatisch vom Browser erstellt wird, wenn das Applet geladen wird.

Wenn der Anwender nun mit der Maus klickt, wird in dem Moment, wo er die Maustaste losläßt, die Methode mouseReleased() aufgerufen. Innerhalb dieser Methode wird im obigen Beispiel die Hintergrundfarbe des Java-Applets auf Blau gesetzt.

Der Vorteil der Interfaces beim Reagieren auf Benutzereingaben ist es, dass jede beliebige Klasse unabhängig davon, wessen Kindklasse sie ist, auf Benutzereingaben reagieren kann, wenn sie nur das entsprechende Interface implementiert. Es ist also nicht notwendig, dass eine Klasse einer anderen ganz bestimmten Klasse aus der Java-Klassenhierarchie untergeordnet ist, um Benutzereingaben entgegennehmen zu können. Dies würde zum Beispiel die Entwicklung von Applets erschweren, weil die Elternklasse bei Applets immer java.applet.Applet sein muss.

Den Einsatz von Interfaces zum Reagieren auf Benutzereingaben lernen Sie im Buch Programmieren in Java: Aufbau ausführlich kennen.


6.5 Aufgaben

Übung macht den Meister

Sie können die Lösungen zu allen Aufgaben in diesem Buch als ZIP-Datei erwerben.

  1. Entwickeln Sie ein Java-Applet, das das Interface java.awt.event.MouseListener implementiert. Setzen Sie die Hintergrundfarbe auf Blau, wenn der Anwender mit der Maus über das Java-Applet fährt. Verlässt die Maus das Java-Applet, soll die Hintergrundfarbe auf Rot gesetzt werden. Die beiden Methoden, die vom Interface java.awt.event.MouseListener zu definieren sind, sind mouseEntered() und mouseExited().

  2. Entwickeln Sie ein Interface namens Fliegen, das eine Methode fliegen() deklariert. Diese Methode soll keinen Rückgabewert besitzen und keine Parameter erwarten. Entwickeln Sie dann eine Klasse namens Biene, die das Interface Fliegen implementiert. Geben Sie in der zu implementierenden Methode "Summsumm" auf die Standardausgabe aus. Kompilieren Sie Ihren Code, um ihn auf Fehlerfreiheit zu überprüfen.

  3. Entwickeln Sie eine Klasse namens Fledermaus, die das Interface Fliegen aus Aufgabe 2 implementiert. Geben Sie in der zu implementierenden Methode "Flatterflatter" auf die Standardausgabe aus. Kompilieren Sie Ihren Code, um ihn auf Fehlerfreiheit zu überprüfen.

  4. Entwickeln Sie eine Java-Application und erstellen Sie innerhalb der Methode main() ein Objekt basierend auf der Klasse Biene aus Aufgabe 2 und ein Objekt basierend auf der Klasse Fledermaus aus Aufgabe 3. Rufen Sie eine neu zu definierende Methode abflug() auf, der Sie einmal das Objekt vom Typ Biene und einmal das Objekt vom Typ Fledermaus übergeben. Die Methode abflug() soll keinen Rückgabewert besitzen und ein Objekt vom Typ des Interfaces Fliegen erwarten. Rufen Sie für den Parameter vom Typ Fliegen innerhalb der Methode abflug() die Methode fliegen() auf, und kompilieren und führen Sie die Anwendung dann aus.

  5. Modifizieren Sie das in Aufgabe 2 entwickelte Interface Fliegen und wandeln Sie es in eine abstrakte Klasse um. Passen Sie Ihre Klassen Biene und Fledermaus aus Aufgabe 2 und 3 so an, dass die in Aufgabe 4 entwickelte Java-Application immer noch funktioniert. Ändern Sie nicht die für Aufgabe 4 entwickelte Klasse, die die Methode main() enthält.

  6. Entwickeln Sie eine Klasse namens Flugzeug derart, dass Sie ein Objekt vom Typ dieser Klasse erstellen und es in der für Aufgabe 4 entwickelten Java-Application der Methode abflug() übergeben können.

  7. Entwickeln Sie eine Klasse namens Maus, die von der Klasse java.applet.Applet abgeleitet wird und die das Interface java.awt.event.MouseListener implementiert. Der Anweisungsblock der zu implementierenden Methoden soll leer sein. Erstellen Sie dann eine Klasse MyApplet, die Sie von der Klasse Maus ableiten. Wenn der Anwender mit der Maus in die Applet-Oberfläche klickt, soll beim Loslassen der Maustaste die Hintergrundfarbe auf Blau gesetzt werden.