Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

 
Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Imperative Sprachkonzepte
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Eigene Klassen schreiben
6 Objektorientierte Beziehungsfragen
7 Ausnahmen müssen sein
8 Äußere.innere Klassen
9 Besondere Typen der Java SE
10 Generics<T>
11 Lambda-Ausdrücke und funktionale Programmierung
12 Architektur, Design und angewandte Objektorientierung
13 Komponenten, JavaBeans und Module
14 Die Klassenbibliothek
15 Einführung in die nebenläufige Programmierung
16 Einführung in Datenstrukturen und Algorithmen
17 Einführung in grafische Oberflächen
18 Einführung in Dateien und Datenströme
19 Einführung ins Datenbankmanagement mit JDBC
20 Einführung in <XML>
21 Testen mit JUnit
22 Bits und Bytes und Mathematisches
23 Die Werkzeuge des JDK
A Java SE-Paketübersicht
Stichwortverzeichnis


Download:

- Beispielprogramme, ca. 35,4 MB


Buch bestellen
Ihre Meinung?



Spacer
<< zurück
Java ist auch eine Insel von Christian Ullenboom

Einführung, Ausbildung, Praxis
Buch: Java ist auch eine Insel


Java ist auch eine Insel

Pfeil 8 Äußere.innere Klassen
Pfeil 8.1 Geschachtelte (innere) Klassen, Schnittstellen, Aufzählungen
Pfeil 8.2 Statische innere Klassen und Schnittstellen
Pfeil 8.3 Mitglieds- oder Elementklassen
Pfeil 8.3.1 Exemplare innerer Klassen erzeugen
Pfeil 8.3.2 Die this-Referenz
Pfeil 8.3.3 Vom Compiler generierte Klassendateien *
Pfeil 8.3.4 Erlaubte Modifizierer bei äußeren und inneren Klassen
Pfeil 8.3.5 Innere Klassen greifen auf private Eigenschaften zu
Pfeil 8.4 Lokale Klassen
Pfeil 8.4.1 Beispiel mit eigener Klassendeklaration
Pfeil 8.4.2 Lokale Klasse für einen Timer nutzen
Pfeil 8.5 Anonyme innere Klassen
Pfeil 8.5.1 Nutzung einer anonymen inneren Klasse für den Timer
Pfeil 8.5.2 Umsetzung innerer anonymer Klassen *
Pfeil 8.5.3 Konstruktoren innerer anonymer Klassen
Pfeil 8.6 Zugriff auf lokale Variablen aus lokalen inneren und anonymen Klassen *
Pfeil 8.7 this in Unterklassen *
Pfeil 8.8 Zum Weiterlesen
 

Zum Seitenanfang

8.5Anonyme innere Klassen Zur vorigen ÜberschriftZur nächsten Überschrift

Anonyme Klassen gehen noch einen Schritt weiter als lokale Klassen: Sie haben keinen Namen und erzeugen immer automatisch ein Objekt; Klassendeklaration und Objekterzeugung sind zu einem Sprachkonstrukt verbunden. Die allgemeine Notation ist folgende:

new KlasseOderSchnittstelle() { /* Eigenschaften der inneren Klasse */ }

In dem Block geschweifter Klammern lassen sich nun Methoden und Attribute deklarieren oder Methoden überschreiben. Hinter new steht der Name einer Klasse oder Schnittstelle:

  • new Klassenname(Optionale Argumente) { }. Steht hinter new ein Klassentyp, dann ist die anonyme Klasse eine Unterklasse von Klassenname. Es lassen sich mögliche Argumente für den Konstruktor der Basisklasse angeben (das ist zum Beispiel dann nötig, wenn die Oberklasse keinen Standard-Konstruktor deklariert).

  • new Schnittstellenname() { }. Steht hinter new der Name einer Schnittstelle, dann erbt die anonyme Klasse von Object und implementiert die Schnittstelle Schnittstellenname. Implementiert sie nicht die Operationen der Schnittstelle, ist das ein Fehler; wir hätten nichts davon, denn dann hätten wir eine abstrakte innere Klasse, von der sich kein Objekt erzeugen lässt.

Für anonyme innere Klassen gilt die Einschränkung, dass keine zusätzlichen extends- oder implements-Angaben möglich sind. Ebenso sind keine eigenen Konstruktoren möglich und nur Objektmethoden und finale statische Variablen erlaubt.

 

Zum Seitenanfang

8.5.1Nutzung einer anonymen inneren Klasse für den Timer Zur vorigen ÜberschriftZur nächsten Überschrift

Eben gerade haben wir für den Timer extra eine neue lokale Klasse deklariert, aber genau genommen haben wir diese nur einmal nutzen müssen, nämlich um ein Exemplar zu bilden und scheduleAtFixedRate(…) übergeben zu können. Das ist ein perfektes Szenario für anonyme innere Klassen. Aus

class SportReminderTask extends TimerTask {

@Override public void run() { … }

}

new Timer().scheduleAtFixedRate( new SportReminderTask(), … );

wird

Listing 8.8com/tutego/insel/inner/ShorterSportReminder.java, main()

new Timer().scheduleAtFixedRate( new TimerTask() {

@Override public void run() {

System.out.println( "Los, …" );

}

},

0 /* ms delay */,

1000 /* ms period */);

Im Kern ist es also eine Umwandlung von new SportReminderTask() in new TimerTask() { }. Von dem Klassennamen SportReminderTask ist nichts mehr zu sehen, das Objekt ist anonym.

[»]Hinweis

Eine innere Klasse kann Methoden der Oberklasse überschreiben, Operationen aus Schnittstellen implementieren und sogar neue Eigenschaften anbieten:

Listing 8.9com/tutego/insel/inner/ObjectWithQuote.java, main()

String s = new Object() {

String quote( String s ) {

return String.format( "'%s'", s );

}

}.quote( "Cora" );

System.out.println( s ); // 'Cora'

Der neu deklarierte anonyme Typ hat eine Methode quote(String), die direkt aufgerufen werden kann. Ohne diesen direkten Aufruf ist die quote(…)-Methode aber unsichtbar, denn der Typ ist ja anonym, und so sind nur die Methoden der Oberklasse (bei uns Object) bzw. der Schnittstelle bekannt. (Wir lassen die Tatsache außen vor, dass eine Anwendung mit Reflection auf die Methoden zugreifen kann.)

 

Zum Seitenanfang

8.5.2Umsetzung innerer anonymer Klassen * Zur vorigen ÜberschriftZur nächsten Überschrift

Auch für innere anonyme Klassen erzeugt der Compiler eine normale Klassendatei. Wir haben gesehen, dass der Java-Compiler bei einer »normalen« inneren Klasse die Notation ÄußereKlasse$InnereKlasse wählt. Das klappt bei anonymen inneren Klassen natürlich nicht mehr, da uns der Name der inneren Klasse fehlt. Der Compiler wählt daher folgende Notation für Klassennamen: InnerToStringDate$1. Falls es mehr als eine innere Klasse gibt, folgen $2, $3 usw.

 

Zum Seitenanfang

8.5.3Konstruktoren innerer anonymer Klassen Zur vorigen ÜberschriftZur nächsten Überschrift

Der Compiler setzt anonyme Klassen in normale Klassendateien um. Jede Klasse kann einen eigenen Konstruktor deklarieren, und auch für anonyme Klassen sollte das möglich sein, um Initialisierungscode dort hineinzusetzen.

Wir wollen eine innere Klasse schreiben, die Unterklasse von java.awt.Point ist. Sie soll die toString()-Methode überschreiben:

Listing 8.10com/tutego/insel/inner/InnerToStringPoint.java, main()

Point p = new Point( 10, 12 ) {

@Override public String toString() {

return "(" + x + "," + y + ")";

}

};



System.out.println( p ); // (10,12)

Die anonyme Unterklasse wird also durch den normalen Konstruktor von Point initialisiert.

Exemplarinitialisierungsblöcke bei inneren anonymen Klassen

Da aber anonyme Klassen keinen Namen haben, muss für Konstruktoren ein anderer Weg gefunden werden. Hier helfen Exemplarinitialisierungsblöcke, also Blöcke in geschweiften Klammern direkt innerhalb einer Klasse, die wir schon in Kapitel 5, »Eigene Klassen schreiben«, vorgestellt haben. Exemplarinitialisierer gibt es ja eigentlich gar nicht im Bytecode, sondern der Compiler setzt den Programmcode automatisch in jeden Konstruktor. Obwohl anonyme Klassen keinen direkten Konstruktor haben können, gelangt doch über den Exemplarinitialisierer Programmcode in den Konstruktor der Bytecode-Datei.

Dazu ein Beispiel: Die anonyme Klasse ist eine Unterklasse von Point und initialisiert im Konstruktor einen Punkt mit Zufallskoordinaten. Aus diesem speziellen Punkt-Objekt lesen wir dann die Koordinaten wieder aus:

Listing 8.11com/tutego/insel/inner/AnonymousAndInside.java, main()

java.awt.Point p = new java.awt.Point() {

{

x = (int)(Math.random() * 1000); y = (int)(Math.random() * 1000);

}

};



System.out.println( p.getLocation() ); // java.awt.Point[…



System.out.println( new java.awt.Point( -1, 0 ) {{

y = (int)(Math.random() * 1000);

}}.getLocation() ); // java.awt.Point[x=-1,y=...]

Sprachlichkeit

Wegen der beiden geschweiften Klammen heißt diese Variante auch Doppelklammer-Initialisierung (engl. double brace initialization).

Die Doppelklammer-Initialisierung ist kompakt, wenn etwa Datenstrukturen oder hierarchische Objekte initialisiert werden sollen.

[zB]Beispiel *

Im folgenden Beispiel erwartet appendText(…) ein Objekt vom Typ HashMap, das durch den Trick direkt initialisiert wird:

String s = new DateTimeFormatterBuilder()

.appendText( ChronoField.AMPM_OF_DAY,

new HashMap<Long, String>() {{ put(0L, "früh");put(1L,"spät" ); }} )

.toFormatter().format( LocalTime.now() );

System.out.println( s );

Im nächsten Beispiel bauen wir eine geschachtelte Map, das ist ein Assoziativspeicher. Der enthält an einem Punkt wieder einen anderen Assoziativspeicher:

Map<String,Object> map = new HashMap<String,Object>() {{

put( "name", "Chris" );

put( "address", new HashMap<String,Object>() {{

put( "street", "Feenallee 1" );

put( "city", "Elefenberg" );

}} );

}};

Warnung

Die Doppelklammerinitialisierung ist nicht ganz »billig«, da eine Unterklasse aufgebaut wird, also neuer Bytecode generiert wird. Zudem hält die innere Klasse eine Referenz auf die äußere Klasse fest. Des Weiteren kann es Probleme mit equals(…) geben, da wir mit der Doppelklammerinitialisierung eine Unterklasse schaffen, die vielleicht mit equals(…) nicht mehr gültig verglichen werden kann, denn die Class-Objekte sind jetzt nicht mehr identisch. Das spricht in der Summe eher gegen diese Konstruktion.

Gar nicht super() *

Innerhalb eines »anonymen Konstruktors« kann kein super(…) verwendet werden, um den Konstruktor der Oberklasse aufzurufen. Dies liegt daran, dass automatisch ein super(…) in den Initialisierungsblock eingesetzt wird. Die Parameter für die gewünschte Variante des (überladenen) Oberklassen-Konstruktors werden am Anfang der Deklaration der anonymen Klasse angegeben. Dies zeigt das folgende Beispiel:

System.out.println( new java.awt.Point( -1, 0 ) {{

y = (int)(Math.random() * 1000);

}}.getLocation() ); // java.awt.Point[x=-1,y=...]

[zB]Beispiel

Wir initialisieren ein Objekt BigDecimal, das beliebig große Ganzzahlen aufnehmen kann. Im Konstruktor der anonymen Unterklasse geben wir anschließend den Wert mit der geerbten toString()-Methode aus:

new java.math.BigDecimal( "12345678901234567890" ) {{

System.out.println( toString() );

}};

 


Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.

>> Zum Feedback-Formular
<< zurück
 Zum Katalog
Zum Katalog: Java ist auch eine Insel Java ist auch eine Insel

Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?

Ihre Meinung



 Buchempfehlungen
Zum Katalog: Java ist auch eine Insel

Java ist auch eine Insel




Zum Katalog: Java SE 9-Standard-Bibliothek

Java SE 9-Standard-Bibliothek




Zum Katalog: Professionell entwickeln mit Java EE 8

Professionell entwickeln mit Java EE 8




Zum Katalog: Entwurfsmuster

Entwurfsmuster




Zum Katalog: IT-Projektmanagement

IT-Projektmanagement




 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich

InfoInfo



 

 


Copyright © Rheinwerk Verlag GmbH 2017

Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

 

[Rheinwerk Computing]



Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de