Nach den bisher vorgestellten Prinzipien erfordert die Implementierung eines GUI die Implementierung von vielen Listenern und führt zur Erzeugung sehr vieler Klassen. Java erlaubt hier die Implementierung von anoymen, inneren Klassen die nur im Kontext einer bestimmten Klasse existieren und den Namensraum der Klassen nicht unnötig belasten.
Innere Klassen
Innere Klassen helfen es zu vermeiden, dass man Klassen veröffentlicht die nur von genau einer anderen Klasse benutzt werden. Innere Klassen werden syntaktisch wie normale Klassen implementiert. Der einzige Unterschied ist, dass sie im Block einer äusseren Klasse implementiert werden. Sie werden in der äusseren Klasse mit dem gleichen Block der äusseren Klasse wie die Klassenvariablen und Methoden der äusseren Klasse implementiert.
Die in der Vorlesung vorgestellten inneren Klassen sind Elementklassen.
| Definition Elementklasse |
|---|
|
Elementklassen sind wie Instanzmethoden und Instanzvariablen Elemente einer (anderen) Klasse. Sie werden auf der gleichen Blockebene wie Instanzmethoden und Instanzvariablen implementiert. Sie haben den Zugriffschutz wie Instanzmethoden und Instanzvariablen. |
Innere Klassen können auch als lokale Klasse innerhalb eines beliebigen Blocks implementiert werden. Diese Variante ist nicht Gegenstand der Vorlesung
Die inneren Klassen gehören zum Paket der äusseren Klasse. Import-Kommandos müssen in der äusseren Klasse implementiert werden.
| Besondere Eigenschaften von Elementklassen |
|---|
Instanzen von Elementklassen sind Koponenten des umgebenden Objekts! |
Das vorhergehende Beispiel kann jetzt wie folgt implementiert werden:
package Kurs2.Swing;
import java.awt.event.MouseAdapter;import java.awt.event.MouseEvent;import javax.swing.JButton;import javax.swing.JFrame;public class MouseAdapterInnereKlasseTest {class MyMouseListener extends MouseAdapter {public void mouseClicked(MouseEvent mEvent) {System.out.println("MouseClick wurde auf Position ["+ mEvent.getX() + ","+ mEvent.getY() + "] "+ mEvent.getClickCount() + " mal geklickt");}}public MouseAdapterInnereKlasseTest() {erzeugeGUI();}public static void main(String[] args) {MouseAdapterInnereKlasseTest mat =new MouseAdapterInnereKlasseTest();}private void erzeugeGUI() {JFrame myJFrame = new JFrame("Mouse Click Innere Klasse Test");myJFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);JButton jb = new JButton("Hier drücken");jb.addMouseListener(new MyMouseListener());myJFrame.getContentPane().add(jb);myJFrame.pack();myJFrame.setVisible(true);}}
Die Unterschiede sind die Folgenden:
- Die Klasse MouseAdapterInnereKlasseTest muss nicht mehr von MouseAdapter abgeleitet werden oder einen MouseEvent implementieren
- Es wird eine eigene innere Klasse MyMouseClicked implementiert die nicht ausserhalb der umgebenden Klasse bekannt ist.
- Die Klasse MyMouseClicked iplementiert das MouseAdapter
- Beim Hinzufügen eines Listeners zum Button wird eine Instanz der inneren Klasse erzeugt
Diese innere Klasse hat für den Entwickler den Vorteil, dass er keine neuen Klassen nach aussen hin bekanntmachen muss. Die Implementierung des Listener erfolgt in der gleichen Datei. Die Implementierung des Listener ist also visuell näher als wenn sie in einer eigenen Klasse und einer eigenen Datei geschehen würde.
Anonyme, innere Klasse
Für Swing wurde das Konzept der anonymen, inneren Klasse entwickelt.
| Definition Anonyme, innere Klasse |
|---|
|
Eine anonyme, innere Klasse ist eine lokale Klasse ohne Namen die innerhalb eines Ausdrucks (Block) definiert und instanziiert wird. |
Anonyme, innere Klassen haben keinen Namen und daher auch keine Konstruktoren. Sie werden typischerweise als Implementierungen für Adapterklassen oder Schnittstellen verwendet.
Beispiel
Anonyme, innere Klassen erlauben die benötigte Listenerimplementierung noch eleganter durchzuführen:
An der Stelle an der eine Instanz eines Listeners benötigt wird kann man auch direkt eine vollständige Klasse implementieren und instanziieren.
Das folgende Beispiel hat die gleiche Funktion wie das vorgehende Beispiel mit der Implementierung einer inneren Klasse. Es kommt aber ohne einen eigenen Klassennamen aus:
package Kurs2.Swing;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
public class MouseAdapterInnereAnonymeKlasseTest {
public MouseAdapterInnereAnonymeKlasseTest() {
erzeugeGUI();
}
public static void main(String[] args) {
MouseAdapterInnereAnonymeKlasseTest mat =
new MouseAdapterInnereAnonymeKlasseTest ();
}
private void erzeugeGUI() {
JFrame myJFrame = new JFrame("Mouse Click Adapter Test");
myJFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton jb = new JButton("Hier drücken");
jb.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent mEvent) {
System.out.println("MouseClick wurde auf Position ["
+ mEvent.getX() + ","
+ mEvent.getY() + "] "
+ mEvent.getClickCount() + " mal geklickt");
}
});
myJFrame.getContentPane().add(jb);
myJFrame.pack();
myJFrame.setVisible(true);
}
}Die Unterschiede sind die Folgenden:
- Die Klasse MouseAdapterInnereAnonymeKlasseTest muss nicht mehr von MouseAdapter abgeleitet werden oder einen MouseEvent implementieren
- Beim Hinzufügen eines Listeners zum Button wird
- mit dem new Operator eine Instanz einer anonymen Klasse angelegt, die die abstrakte Klasse MouseAdapter implementiert. Sie ist anonym da sie selbst keinen Namen besitzt.
- die anonyme Klasse wird innerhalb der Klasse MouseAdapterInnereAnonymKlasseTest soweit wie nötig implementiert um aus der abstrakten Oberklasse eine normale Klasse zu erzeugen
Diese "Hilfskonstruktion" hat für den Entwickler eine Reihe von Vorteilen:
- Das Ereignis kann textuell sehr nahe an der Erzeugung der Komponente implementiert werden. Der Code wird übersichtlicher
- Es müssen keine neuen Klassen mit eigenen Namen erzeugt werden. Hierdurch wird die gesamte Klassenhierarchie übersichtlicher und deutlich kleiner.
Statische innere Klassen, nicht anonyme lokale Klassen
... sind nicht Gegenstand dieser Vorlesung.
