Folien, pdf

Werbung
Info B VL 10: Innere Klassen
Objektorientiere Programmierung in Java
2003
Ute Schmid (Vorlesung)
Elmar Ludwig (Übung)
FB Mathematik/Informatik, Universität Osnabrück
Info B VL 10: Innere Klassen – p.221
Innere Klassen
Bisher: “top-level” Klassen (direkte Mitglieder eines
Pakets)
Seit Java 1.1: Innere Klassen: definiert innerhalb einer
anderen Klasse (Komponente einer Klasse, ähnlich
Felder und Methoden)
Vier Arten von inneren Klassen:
Member Classes (“echte” innere Klasse)
Static Member Classes (Nested Top-Level Classes)
Local Classes
Anonymous Classes
Info B VL 10: Innere Klassen – p.222
Member Klassen / Beispiel
Ein Auto besteht aus vielen Teilen – Motor,
Gangschaltung, Auspuff, etc.
Manche Teile bilden sinnvollerweise eine eigene
Klasse, aber können dennoch nicht unabhängig vom
Auto existieren.
Beispiel: Klimaanlage
Interaktion zwischen Klimaanlage und Auto ist
notwendig.
Leistung der Klimaanlage ist abhängig von
Geschwindigkeit des Autos. Je langsamer das Auto
fährt, desto mehr Energie muss die Klimaanlage
zum Kühlen aufbringen.
Lösung: Member Klasse
Info B VL 10: Innere Klassen – p.223
‘AutoAirCondition’
class AirConditioner {
...
public float getTemperatureMin() { };
public float getTemperatureMax() { };
}
class Automobile {
private Engine engine;
private GearBox gearBox;
...
private class AutoAirConditioner extends AirConditioner {
private float default = ...;
private float factor = ...;
...
public float getTargetTemperature () {
float temperature = default - factor * engine.getSpeed();
...
} }
public AirConditioner getAirConditioner () {
return new AutoAirConditioner();
}
}
Info B VL 10: Innere Klassen – p.224
‘AirConditioner’ – Erläuterung (1)
Der AutoAirConditioner ist abhängig von Parametern
eines bestimmten Autos
Beachte: Ein Objekt der inneren Klasse kann nur
zusammen mit einem Objekt der umschließenden
Klasse existieren
Erst neues Automobil erzeugen, dann die
AutoAirCondition!
Es ist nicht möglich, ein Objekt vom Typ
AutoAirCondition zu erzeugen, ohne dass ein
Auto, zu dem diese Klimaanlage gehört existiert.
Info B VL 10: Innere Klassen – p.225
‘AirConditioner’ – Erläuterung (2)
Innere Klasse ist privat:
Andere Klassen/Objekte können nur auf das
öffentliche Inferface (AirConditioner) zugreifen.
Die umschließende Klasse hat eine Methode, um
ein “Handle” (Referenz) auf die öffentlichen Teile
des Objekts der inneren Klasse zu liefern
(getAirConditioner).
Beachte: return new
AutoAirConditioner() ist explizit: return
this.new AutoAirConditioner()
Alternatives Beispiel: Organe können nicht ohne
Körper existieren.
Weitere Beispiele: Enumerator (bzw. Iterator)
Im Kontext von Auto: z.B. Aufzählen aller Schrauben,
um z.B. mittlere Größe, mittlere Kosten zu bestimmen.
Info B VL 10: Innere Klassen – p.226
Eigenschaften von Member Klassen (1)
Member-Klassen sind die typischen, “echten” inneren
Klassen.
Member-Klassen sind wie Instanz-Felder und
-Methoden mit einer Instanz der Klasse, in der sie
definiert sind, assoziiert.
Also: Zugriff auf alle Komponenten der
umschliessenden Klasse.
Member-Klassen können beliebig tief geschachtelt
werden. D. h., eine innere Klasse kann weitere innere
Klassen enthalten.
Eine Member-Klasse kann mit allen
Sichtbarkeits-Modifikatoren deklariert werden.
Name muss verschieden vom Namen der
umschliessenden Klasse sein.
Info B VL 10: Innere Klassen – p.227
Eigenschaften von Member Klassen (2)
Member-Klassen dürfen keine statischen
Komponenten enthalten. Ausnahme: static und
final deklarierte Konstanten.
Interfaces können nicht als Member-Klassen definiert
werden, da Interfaces keine Instanz-Variablen besitzen
dürfen (also kein this-Verweis möglich).
Info B VL 10: Innere Klassen – p.228
Eigenschaften von Member Klassen (3)
Wichtigstes Merkmal: Zugriff auf Instanz-Felder und
-Methoden der umschliessenden Klasse.
current < numOfEls
Wie funktioniert explizite Referenz?
this.current < this.numOfEls
Problem: this.numOfEls ist nicht zulässig (this
bezieht sich auf Enumerator-Objekt)
Erweiterte Syntax:
this.current < MyListMC.this.numOfEls
Diese Zugriffsform ist dann notwendig, wenn man sich
auf eine Komponente einer äusseren Klasse beziehen
will, die denselben Namen hat wie eine Komponente
der inneren Klasse.
Info B VL 10: Innere Klassen – p.229
Eigenschaften von Member Klassen (4)
Analoge Erweiterung der super-Syntax (Zugriff auf
eine überdeckte oder überschriebene Komponente der
Oberklasse der umschliessenden Klasse):
Klassenname .super. feld
Klassenname .super. methode
Ausführung des Member-Klassen Konstruktors
bewirkt, dass die neue Instanz mit dem this Objekt
der umschliessenden Klasse assoziiert wird.
Gleichbedeutende Schreibweisen:
return new
public Enumeration enumerate()
Enumerator();
public Enumeration enumerate()
Enumerator();
return this.new
Info B VL 10: Innere Klassen – p.230
Eigenschaften von Member Klassen (5)
Anstelle der Definition von enumerator() könnte
eine Enumeration auch so erzeugt werden:
MyListMC intlist = new MyListMC(); // Create empty
list
Enumeration enum = intlist.new Enumerator();
// Create Enum for it
Da die umschliessende Instanz implizit den Namen der
umschliessenden Klasse spezifiziert, ist die explizite
Angabe der Klasse ein Syntaxfehler:
Enumeration e = intlist.new MyListMC.Enumerator();
// Syntax error
Info B VL 10: Innere Klassen – p.231
Implementation von Member-Klassen (1)
Erweiterung der Sprache (“syntactic sugar”) aber nicht
der JVM: Java Compiler wandelt Repräsentation von
inneren Klassen entsprechend um.
Compilation in eigene top-level-Datei.
Compiler muss Code so manipulieren, dass Zugriff auf
Komponenten zwischen innerer und äusserer Klasse
funktioniert.
this$0 Feld für jede Member-Klasse (Assoziation mit
Instanz der umschliessenden Klasse; Abspeichern der
entsprechenden Referenz).
Für weitere Referenzen zu umschliessenden Klassen
wird entsprechend weitergezählt (this$1, etc.).
Info B VL 10: Innere Klassen – p.232
Implementation von Member-Klassen (2)
Jeder Member-Klassen Konstruktor erhält einen
zusätzlichen Parameter, um dieses Feld zu
initialisieren.
protected Member-Klassen werden public;
private Member-Klassen werden default-sichtbar.
Info B VL 10: Innere Klassen – p.233
Member-Klassen und Vererbung
Es ist erlaubt, dass eine top-level Klasse als
Unterklasse einer Member-Klasse definiert wird.
Damit hat die Unterklasse keine umschliessende
Klasse, aber ihre Oberklase!
Wegen unklarer Semantik argumentieren einige dafür,
dass diese Art der Vererbung verboten werden soll.
Atsushi Igarashi and Benjamin C. Pierce (2001). On
inner classes. Information and Control.
Die Autoren haben bei der Definition einer
Reduktions-Semantik für innere Klassen und
Vererbung Unterspezifikationen der Sprache Java
aufgedeckt.
Info B VL 10: Innere Klassen – p.234
Beispiel 1
// A top-level class that extends a member class
class SpecialEnumerator extends MyListMC.Enumerator {
// The constructor must explicitely specify a
// containing instance
// when invoking the superclass constructor
public SpecialEnumerator(MyListMC l) { l.super(); }
// Rest of class omitted
}
Info B VL 10: Innere Klassen – p.235
Beispiel 2
(Igarashi and Pierce, 2001)
class C {
void who(){ System.out.println("I’m a C object"); }
class D extends C{
void m(){ C.this.who(); }
void who(){ System.out.println("I’m a C.D object"); }
}
public static void main(String[] args){
new C().new D().m();
}
}
Info B VL 10: Innere Klassen – p.236
Vererbung und Namenskonflikte
Zwei hierarchische Strukturen: Klassenhierarchie und
Enthaltensein-Hierarchie (Containment)
Es können Namenskonflikte zwischen vererbten
Komponenten (Oberklasse) und Komponenten der
umschliessenden Klasse auftreten.
class A { int x; }
class B {
int x;
class C extends A{
x;
// inherited field
this.x; // inherited field
B.this.x; // field of containing class
} }
Info B VL 10: Innere Klassen – p.237
Static Member Classes / Beispiel
Ein Autoradio gehört als Teil zum Auto, seine
Eigenschaften sind aber unabhängig vom Auto selbst.
Autoradios sind Objekte, die unabhängig von einem
konkreten Auto existieren können: diese Klassen
benötigen keinen Zugriff auf Instanz-Felder und/oder
-Methoden der Automobil-Klasse.
Statische innere Klassen dienen vor allem der
Strukturierung von Programmcode.
Info B VL 10: Innere Klassen – p.238
‘AutoRadio’
interface Radio {
void setVolume ();
...
}
class Automobile {
private Engine engine;
private GearBox gearBox;
.....
private static class AutoRadio extends Radio {
private int channel = ...;
private float volume = ...;
...
public void setVolume () { ... }
}
public Radio getRadio () { return new AutoRadio(); }
}
Info B VL 10: Innere Klassen – p.239
Eigenschaften von Static Members (1)
Während Member-Klassen analog zu Instanz-Feldern
und -Methoden zu sehen sind, sind static member
classes ähnlich wie Klassen-Felder und -Methoden zu
verstehen. (“class class”)
Sie haben Zugriff auf alle statischen Komponenten der
umschliessenden Klasse.
Static member classes werden auch als nested
top-level classes bezeichnet.
Interfaces dürfen nur als static members definiert
werden.
Static Klassen können in einem Interface deklariert
werden.
Info B VL 10: Innere Klassen – p.240
Eigenschaften von Static Members (2)
Static member classes (und Interfaces) werden wie
top-level Klassen behandelt. Sie sind nicht mit einer
Instanz der umschliessenden Klasse assoziiert (also:
kein umschliessendes this-Objekt).
Deklaration mit Zugriffsmodifikator genau wie für
andere Komponenten.
Name muss verschieden vom Namen der
umschliessenden Klasse sein.
(unqualifizierter) Zugriff auf alle (auch privaten)
statischen Komponenten der umschliessenden Klasse
(inklusiver weiterer static member classes).
Methoden der umschliessenden Klasse haben Zugriff
auf alle Komponenten der Member-Klasse.
Info B VL 10: Innere Klassen – p.241
Eigenschaften von Static Members (3)
Zugriff von externen Klassen: mit qualifiziertem
Namen.
Automobile.AutoRadio
Vorteil: Strukturierung, paket-ähnliche Organisation für
Klassen innerhalb einer Datei.
Info B VL 10: Innere Klassen – p.242
Nutzung Innerer Klassen
Member-Klassen (“echte” wie static deklarierte) sollen
immer dann verwendet werden, wenn eine Referenz
“von innen nach aussen” benötigt wird.
Auf der Modellierungsebene heisst das: Ein Objekt ist
aus anderen (inneren) Objekten aufgebaut, es kann
nicht ohne diese inneren Objekte existieren, und die
inneren Objekte benötigen Information über das
umschliessende Objekt.
Bei Member-Klassen werden Informationen der
umschliessenden Instanz benötigt.
Bei static deklarierten inneren Klassen werden
statische bzw. keine Komponenten der
umschliessenden Klasse benötigt, aber die
umschliessene Klasse kann auf Komponenten der
inneren Klasse zugreifen.
Info B VL 10: Innere Klassen – p.243
Implementation von statischen Members
Compiler generiert zwei Klassen-Dateien, z.B.
Automobile.class und
Automobile$AutoRadio.class (Innere Klasse
AutoRadio wird zu top-level Klasse).
Compiler qualifiziert Ausdrücke, die auf statische
Komponenten der umschliessenden Klasse zugreifen,
mit dem Klassennamen.
Da auch auf private Komponenten zugegriffen werden
darf: Automatische Generierung von nicht-privaten
Zugriffsmethoden (mit Default-Zugriffsrechten,
paket-weit) und Umwandlung der entsprechenden
Ausdrücke.
Info B VL 10: Innere Klassen – p.244
Lokale Klassen / Beispiel
Alternative Modellierungsidee für die Automobil-Klasse
Da die Klasse AutoAirConditioner nur einmal, innerhalb
der Methode getAutoAirConditioner(), benötigt
wird, kann die Klasse lokal definiert werden.
siehe auch Enumerator-Beispiel: MyListLC.java
Info B VL 10: Innere Klassen – p.245
‘AutoAirConditioner’
class AirConditioner {
...
public float getTemperatureMin() { };
public float getTemperatureMax() { };
}
class Automobile {
private Engine engine;
private GearBox gearBox;
...
public AirConditioner getAirConditioner () {
class AutoAirConditioner extends AirConditioner {
private float default = ...;
private float factor = ...;
...
public float getTargetTemperature () {
float temperature =
default - factor * engine.getSpeed();
} }
return new AutoAirConditioner();
} }
Info B VL 10: Innere Klassen – p.246
Eigenschaften Lokaler Klassen (1)
Nicht Komponente einer Klasse, sondern innerhalb
eines Blocks definiert.
Typischerweise innerhalb einer Methode, auch
innerhalb von Initialisierungsblöcken.
Analogie: Lokale Variable – lokale Klasse; Instanz-Feld
– Member-Klasse
Geltungsbereich: Innerhalb des Blocks
Java ist eine lexically scoped Sprache:
Geltungsbereich von Variablen ist durch ihre Position
im Code definiert: innerhalb der geschweiften
Klammern, in die sie eingeschlossen sind.
Wenn eine Member-Klasse nur innerhalb einer
einzigen Methode der umschliessenden Klasse
genutzt wird, kann sie ebenso gut als lokale Klasse
definiert werden.
Info B VL 10: Innere Klassen – p.247
Eigenschaften Lokaler Klassen (2)
Name muss verschieden vom Namen der
umschliessenden Klasse sein.
Interfaces können nicht lokal deklariert werden.
Wie Member-Klassen: Zugriff auf alle Komponenten
der umschliessenden Klasse.
Zusätzlich auf alle im Block sichtbaren final
Parameter und Variablen.
Keine Sichtbarkeits-Modifikatoren erlaubt.
Info B VL 10: Innere Klassen – p.248
Eigenschaften Lokaler Klassen (3)
Keine statischen Felder erlaubt (Ausnahme: static
und final deklarierte Konstanten. (wie
Member-Klassen)
Zugriff auf sichtbare Variablen und Parameter nur,
wenn diese final deklariert sind, weil die
Lebensdauer einer Instanz einer lokalen Klasse länger
sein kann als die Ausführung der Methode, in der sie
definiert ist. D.h., die lokale Klasse benötigt eine
private Kopie aller lokalen Variablen, die sie verwendet
(automatisch vom Compiler erzeugt). Einzige
Möglichkeit, Konsistenz zu garantieren (lokale
Variablen und deren Kopie bleiben identisch): final.
Info B VL 10: Innere Klassen – p.249
public class A {
int f() {
int i = 5;
class B {
int j = i;
}
i = i - 1;
return new B().j;
}
public static void main (String[] args) {
A a = new A();
int value1 = a.f;
int value2 = a.f; // should be same value !
}
}
Info B VL 10: Innere Klassen – p.250
Eigenschaften Lokaler Klassen (4)
Erweiterung der Java-Syntax: final-Modifikator darf
nicht nur für lokale Variablen, sondern auch für
Parameter von Methoden und Exception Parameter im
catch-Statement angegeben werden.
Wie Member-Klassen haben lokale Klassen Zugriff auf
die Instanz der umschliessenden Klasse, falls sie nicht
in einer Klassenmethode vereinbart werden
(qualifiziertes this um auf Komponenten der
umschliessenden Klasse zuzugreifen).
Info B VL 10: Innere Klassen – p.251
Geltungsbereich Lokaler Klassen
class A { protected char a = ’a’; }
class B { protected char b = ’b’; }
public class C extends A {
private char c = ’c’;
// visible to local class
public static char d = ’d’;
public void createLocalObject(final char e) {
final char f = ’f’;
int i = 0; // not final, not usable by local class
class Local extends B {
char g = ’g’;
public void printVars(){
System.out.println(g); // this.g, field of Local
System.out.println(f); // final local variable
System.out.println(e); // final local parameter
System.out.println(d); // C.this.d, field of containing class
System.out.println(c); // C.this.c
System.out.println(b); // inherited by Local
System.out.println(a); // inherited by containing class
}
}
Local l = new Local(); // Create instance of Local
l.printVars();
// call its method
} }
Info B VL 10: Innere Klassen – p.252
Geltungsbereich vs. Objekt-Lebenszeit
public class Weird {
// A static member interface used below
public static interface IntHolder { public int getValue(); }
public static void main(String[] args) {
IntHolder[] holders = new IntHolder[10]; // array to hold 10 objs
for (int i = 0; i < 10; i++) {
// Loop to fill array
final int fi = i; // new for each iteration
class MyIntHolder implements IntHolder {
public int getValue() { return fi; }
}
holders[i] = new MyIntHolder(); // Instantiate local class
}
for(int i = 0; i < 10; i++) System.out.println(holders[i].getValue());
}
}
Info B VL 10: Innere Klassen – p.253
Herunterladen