Galileo Computing < openbook >Galileo 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 Exceptions
7 Äußere.innere Klassen
8 Besondere Klassen der Java SE
9 Generics<T>
10 Architektur, Design und angewandte Objektorientierung
11 Die Klassenbibliothek
12 Einführung in die nebenläufige Programmierung
13 Einführung in Datenstrukturen und Algorithmen
14 Einführung in grafische Oberflächen
15 Einführung in Dateien und Datenströme
16 Einführung in die <XML>-Verarbeitung mit Java
17 Einführung ins Datenbankmanagement mit JDBC
18 Bits und Bytes und Mathematisches
19 Die Werkzeuge des JDK
A Die Klassenbibliothek
Stichwort

Download:
- openbook, ca. 24,5 MB
- Aufgaben, ca. 1,1 MB
- Programme, ca. 12,8 MB
Buch bestellen
Ihre Meinung?

Spacer
Java ist auch eine Insel von Christian Ullenboom
Das umfassende Handbuch
Buch: Java ist auch eine Insel

Java ist auch eine Insel
Galileo Computing
1308 S., 10., aktualisierte Auflage, geb., mit DVD
ca. 49,90 Euro, ISBN 978-3-8362-1802-3
Pfeil7 Äußere.innere Klassen
Pfeil7.1 Geschachtelte (innere) Klassen, Schnittstellen, Aufzählungen
Pfeil7.2 Statische innere Klassen und Schnittstellen
Pfeil7.3 Mitglieds- oder Elementklassen
Pfeil7.3.1 Exemplare innerer Klassen erzeugen
Pfeil7.3.2 Die this-Referenz
Pfeil7.3.3 Vom Compiler generierte Klassendateien *
Pfeil7.3.4 Erlaubte Modifizierer bei äußeren und inneren Klassen
Pfeil7.3.5 Innere Klassen greifen auf private Eigenschaften zu
Pfeil7.4 Lokale Klassen
Pfeil7.5 Anonyme innere Klassen
Pfeil7.5.1 Umsetzung innerer anonymer Klassen *
Pfeil7.5.2 Nutzung innerer Klassen für Threads *
Pfeil7.5.3 Konstruktoren innerer anonymer Klassen *
Pfeil7.6 Zugriff auf lokale Variablen aus lokalen inneren und anonymen Klassen *
Pfeil7.7 this in Unterklassen *

Galileo Computing - Zum Seitenanfang

7.3 Mitglieds- oder ElementklassenZur nächsten Überschrift

Eine Mitgliedsklasse (engl. member class), auch Elementklasse genannt, ist ebenfalls vergleichbar mit einem Attribut, nur ist sie nicht statisch (statische innere Klassen lassen sich aber auch als statische Mitgliedsklassen bezeichnen). Deklarieren wir eine innere Mitgliedsklasse Room in House:

Listing 7.2: com/tutego/insel/inner/House.java, Ausschnitt

class House
{
private String owner = "Ich";

class Room
{
void ok()
{
System.out.println( owner );
}
// static void error() { }
}
}

Ein Exemplar der Klasse Room hat Zugriff auf alle Eigenschaften von House, auch auf die privaten. Eine wichtige Eigenschaft ist, dass innere Mitgliedsklassen selbst keine statischen Eigenschaften deklarieren dürfen. Der Versuch führt in unserem Fall zu einem Compilerfehler:

The method error cannot be declared static; static methods can only be declared in a static or top level type

Galileo Computing - Zum Seitenanfang

7.3.1 Exemplare innerer Klassen erzeugenZur nächsten ÜberschriftZur vorigen Überschrift

Um ein Exemplar von Room zu erzeugen, muss ein Exemplar der äußeren Klasse existieren. Das ist eine wichtige Unterscheidung gegenüber den statischen inneren Klassen aus Abschnitt 7.2. Statische innere Klassen existieren auch ohne Objekt der äußeren Klasse.

In einem Konstruktor oder in einer Objektmethode der äußeren Klassen kann einfach mit dem new-Operator ein Exemplar der inneren Klasse erzeugt werden. Kommen wir von außerhalb – oder von einem statischen Block der äußeren Klasse – und wollen wir Exemplare der inneren Klasse erzeugen, so müssen wir bei Elementklassen sicherstellen, dass es ein Exemplar der äußeren Klasse gibt. Java schreibt eine spezielle Form für die Erzeugung mit new vor, die folgendes allgemeine Format besitzt:

referenz.new InnereKlasse(...)

Dabei ist referenz eine Referenz vom Typ der äußeren Klasse. Um in der statischen main()-Methode vom Haus ein Room-Objekt aufzubauen, schreiben wir:

Listing 7.3: com/tutego/insel/inner/House.java, main()

House h = new House();
Room r = h.new Room();

Oder auch in einer Zeile:

Room  r = new House().new Room();

Galileo Computing - Zum Seitenanfang

7.3.2 Die this-ReferenzZur nächsten ÜberschriftZur vorigen Überschrift

Möchte eine innere Klasse In auf die this-Referenz der sie umgebenden Klasse Out zugreifen, schreiben wir Out.this. Wenn Variablen der inneren Klasse die Variablen der äußeren Klasse überdecken, so schreiben wir Out.this.Eigenschaft, um an die Eigenschaften der äußeren Klasse Out zu gelangen:

Listing 7.4: com/tutego/insel/inner/FurnishedHouse.java,FurnishedHouse

class FurnishedHouse
{
String s = "House";

class Room
{
String s = "Room";

class Chair
{
String s = "Chair";

void output()
{
System.out.println( s ); // Chair
System.out.println( this.s ); // Chair
System.out.println( Chair.this.s ); // Chair
System.out.println( Room.this.s ); // Room
System.out.println( FurnishedHouse.this.s ); // House
}
}
}

public static void main( String[] args )
{
new FurnishedHouse().new Room().new Chair().output();
}
}
Hinweis

Elementklassen können beliebig geschachtelt sein, und da der Name eindeutig ist, gelangen wir mit Klassenname.this immer an die jeweilige Eigenschaft.

Betrachten wir das obige Beispiel, dann lassen sich Objekte für die inneren Klassen Room und Chair wie folgt erstellen:

FurnishedHouse h            = new FurnishedHouse();  // Exemplar von FurnishedHouse
FurnishedHouse.Room r = h.new Room(); // Exemplar von Room in h
FurnishedHouse.Room.Chair c = r.new Chair(); // Exemplar von Chair in r
c.out(); // Methode von Chair

Die Qualifizierung mit dem Punkt bei FurnishedHouse.Room.Chair bedeutet nicht automatisch, dass FurnishedHouse ein Paket mit dem Unterpaket Room ist, in dem die Klasse Chair existiert. Die Doppelbelegung des Punkts verbessert die Lesbarkeit nicht gerade, und es droht Verwechslungsgefahr zwischen inneren Klassen und Paketen. Deshalb sollte die Namenskonvention beachtet werden: Klassennamen beginnen mit Großbuchstaben, Paketnamen mit Kleinbuchstaben.


Galileo Computing - Zum Seitenanfang

7.3.3 Vom Compiler generierte Klassendateien *Zur nächsten ÜberschriftZur vorigen Überschrift

Für das Beispiel House und Room erzeugt der Compiler die Dateien House.class und House$Room.class. Damit die innere Klasse an die Attribute der äußeren gelangt, generiert der Compiler automatisch in jedem Exemplar der inneren Klasse eine Referenz auf das zugehörige Objekt der äußeren Klasse. Damit kann die innere Klasse auch auf nicht-statische Attribute der äußeren Klasse zugreifen. Für die innere Klasse ergibt sich folgendes Bild in House$Room.class:

class HouseBorder$Room
{
final House this$0;

House$Room( House house )
{
this$0 = house;
}
// ...
}

Die Variable this$0 referenziert das Exemplar House.this, also die zugehörige äußere Klasse. Die Konstruktoren der inneren Klasse erhalten einen zusätzlichen Parameter vom Typ House, um die this$0-Variable zu initialisieren. Da wir die Konstruktoren sowieso nicht zu Gesicht bekommen, kann uns das egal sein.


Galileo Computing - Zum Seitenanfang

7.3.4 Erlaubte Modifizierer bei äußeren und inneren KlassenZur nächsten ÜberschriftZur vorigen Überschrift

Ist in einer Datei nur eine Klasse deklariert, kann diese nicht privat sein. Private innere Klassen sind aber legal. Statische Hauptklassen gibt es zum Beispiel auch nicht, aber innere statische Klassen sind legitim. Die folgende Tabelle fasst die erlaubten Modifizier noch einmal kompakt zusammen:

Tabelle 7.2: Erlaubte Modifizierer

Modifizierer erlaubt auf äußeren Klassen inneren Klassen äußeren Schnittstellen inneren Schnittstellen
public ja ja ja ja
protected nein ja nein ja
private nein ja nein ja
static nein ja nein ja
final ja ja nein nein
abstract ja ja ja ja

Galileo Computing - Zum Seitenanfang

7.3.5 Innere Klassen greifen auf private Eigenschaften zuZur nächsten ÜberschriftZur vorigen Überschrift

Es ist ein Sonderfall, dass äußere Klassen auf private Eigenschaften der inneren Klasse zugreifen können. Das folgende Beispiel soll das illustrieren:

Listing 7.5: com/tutego/insel/inner/NotSoPrivate.java, NotSoPrivate

public class NotSoPrivate
{
private static class Family { private String dad, mom; }

public static void main( String[] args )
{
class Node { private Node next; }

Node n = new Node();
n.next = new Node();

Family ullenboom = new Family();
ullenboom.dad = "Heinz";
ullenboom.mom = "Eva";
}
}

Eine Klasse Outsider, die in der gleichen Compilationseinheit (also Datei) definiert wird, kann schon nicht mehr auf NotSoPrivate.Family zugreifen und natürlich auch keine Klasse einer anderen Compilationseinheit.

Zugriffsrechte *

Eine innere Klasse kann auf alle Attribute der äußeren Klasse zugreifen. Da eine innere Klasse als ganz normale Klasse übersetzt wird, stellt sich allerdings die Frage, wie sie das genau macht. Auf öffentliche Variablen kann jede andere Klasse ohne Tricks zugreifen, so auch die innere. Und da eine innere Klasse als normale Klassendatei im gleichen Paket sitzt, kann sie ebenfalls ohne Verrenkungen auf paketsichtbare und protected-Eigenschaften der äußeren Klasse zugreifen. Eine innere Klasse kann jedoch auch auf private Eigenschaften zurückgreifen, eine Designentscheidung, die sehr umstritten ist und lange kontrovers diskutiert wurde. Doch wie ist das zu schaffen, ohne gleich die Zugriffsrechte des Attributs zu ändern? Der Trick ist, dass der Compiler eine synthetische statische Methode in der äußeren Klasse einführt:

class House
{
private String owner;

static String access$0( House house )
{
return house.owner;
}
}

Die statische Methode access$0() ist der Helfershelfer, der für ein gegebenes House das private Attribut nach außen gibt. Da die innere Klasse einen Verweis auf die äußere Klasse pflegt, gibt sie diesen beim gewünschten Zugriff mit, und die access$0()-Methode erledigt den Rest.

Für jedes von der inneren Klasse genutzte private Attribut erzeugt der Compiler eine solche Methode. Wenn wir eine weitere private Variable int size hinzunehmen, würde der Compiler ein int access$1(House) generieren.

Hinweis

Problematisch ist das bei Klassen, die in ein Paket hineingeschmuggelt werden. Nehmen wir an, House liegt im Paket p1.p2. Dann kann ein Angreifer seine Klassen auch in ein Paket legen, das p1.p2 heißt. Da die access$XXX()-Methoden paketsichtbar sind, können hineingeschmuggelte Klassen die packetsichtbaren access$XXX()-Methoden aufrufen. Es reicht ein Exemplar der äußeren Klasse, um über einen access$XXX()-Aufruf auf die privaten Variablen zuzugreifen, die eine innere Klasse nutzt. Glücklicherweise lässt sich gegen eingeschleuste Klassen in Java-Archiven leicht etwas unternehmen – sie müssen nur abgeschlossen werden, was bei Java sealing heißt.



Ihr Kommentar

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







<< 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 7 – Mehr als eine Insel





 Java 7 –
 Mehr als eine Insel


Zum Katalog: Android 3






 Android 3


Zum Katalog: Android-Apps entwickeln






 Android-Apps
 entwickeln


Zum Katalog: NetBeans Platform 7






 NetBeans
 Platform 7


Zum Katalog: Einstieg in Eclipse 3.7






 Einstieg in
 Eclipse 3.7


Zum Katalog: Einstieg in Java






 Einstieg
 in Java


Zum Katalog: Einstieg in Java 7






 Einstieg in
 Java 7


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Galileo Press 2011
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.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de