• Keine Ergebnisse gefunden

Innere Klassen

N/A
N/A
Protected

Academic year: 2021

Aktie "Innere Klassen"

Copied!
33
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Info B VL 10: Innere Klassen

Objektorientiere Programmierung in Java 2003

Ute Schmid (Vorlesung) Elmar Ludwig ( ¨ Ubung)

FB Mathematik/Informatik, Universit¨at Osnabr¨uck

(2)

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

(3)

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.

(4)

‘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 () {

(5)

‘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.

(6)

‘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 )

(7)

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

(8)

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).

(9)

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.

(10)

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:

public Enumeration enumerate()

return new Enumerator();

public Enumeration enumerate()

return this.new Enumerator();

(11)

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

(12)

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.).

(13)

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.

(14)

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.

(15)

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

}

(16)

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();

}

}

(17)

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

(18)

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.

(19)

‘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(); }

(20)

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.

(21)

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

(22)

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.

(23)

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

(24)

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.

(25)

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

(26)

‘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();

(27)

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

(28)

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.

(29)

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 .

(30)

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;

(31)

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).

(32)

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

} }

(33)

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());

}

Referenzen

ÄHNLICHE DOKUMENTE

- Geschachtelte Klassen können als privat deklariert werden, so dass sie außerhalb der umfassenden Klasse nicht verwendet werden können. - Geschachtelte Klassen können auf

- Methoden der Klasse Window können Klassennamen weglassen (border = ...; setBorder( 3);) - Klassenkonstruktor wird nie explizit aufgerufen. Zugriff auf nonstatic- Elemente über

• Eine Klassendeklaration kann auch direkt diverse abgeleitete Operationen implementieren, wie z.B. eine Gleichheit, falls es nur ein ≤ gibt... Insofern könnte man damit generisch

 innere Klasse: Die Klasse wird innerhalb einer anderen Klasse definiert..!. (Beachte: der untere, leere Teil wird später

b) So viel Schnee ist aber nicht vorhanden: Es stehen nur 3 ' 400 m 3 Schnee zur Verfügung.. Dieses Aufgabenblatt muss zusammen mit der Arbeit abgegeben werden. Die

Dieses Aufgabenblatt muss zusammen mit der Arbeit abgegeben werden. Ergebnisse ohne Begründung werden nicht bewertet. Jede Aufgabe muss auf ein separates Blatt gelöst

Das Strassennetz auf der Insel besteht aus einer Ringstrasse, welche ganz ohne Steigung die Insel in der Höhe z = 1.5 umrundet, und aus einer weiteren Strasse, die den

Dieses  Aufgabenblatt  muss  zusammen  mit  der  Arbeit  abgegeben  werden... Dieses  Aufgabenblatt  muss  zusammen  mit  der  Arbeit  abgegeben