Innere Klassen in Java Java 1.0: nur top-level Klassen Seit Java Version 1.1: Innere Klassen Deklaration einer Klasse innerhalb einer anderen Klasse Illustration Eigenschaften Vorteile (1) Anwendungsmöglichkeiten Varianten Probleme Literatur Innere Klassen in Java Illustration: Ein Auto hat Räder class Auto{ // auessere Klasse String marke; // Instanz-Variable mit Identifier marke und Typ String class Rad{ // innere Klasse String material; int radius; } Rad linkesRad = new Rad(); // Instanz-Variable mit Initialisierung // alternativ this. new Rad() } (2) Innere Klassen erlauben stärkere Strukturierung von Code! } public class AutoTest{ public static void main(String[] args){ // main Methode Auto a1 = new Auto(); // Instanz a1 vom Typ Auto a1.marke = "VW"; a1.linkesRad.material = "Holz"; a1.linkesRad.radius = 3; System.out.println("Auto a1 hat ein Rad aus "+ a1.linkesRad.material); } Innere Klassen in Java Eigenschaften Innerer Klassen Zugriff: Der Code einer inneren Klasse kann auf alle Felder der umschließenden Klasse zugreifen (mit den einfachen Namen) class Auto{ String marke; class Rad{ String material; int radius; void setMat(){if (marke == "VW") {material = "Gummi";}} // Zugriff auf Feld marke der aeusseren Klasse } Rad linkesRad = new Rad(); void setMatLRad(){linkesRad.setMat();} } } (3) public class AutoTestExt{ public static void main(String[] args){ Auto a1 = new Auto(); a1.marke = "VW"; a1.setMatLRad(); System.out.println("Auto a1 hat ein Rad aus "+ a1.linkesRad.material); } Innere Klassen in Java ... Eigenschaften // Zugriff auf Klasse Rad Zugreifbarkeit: Der Name einer inneren Klasse ist nicht außerhalb ihres Geltungsbereichs zugreifbar class Auto{ ... class Rad{ ... } ... Rad linkesRad = new Rad(); } } public class AutoErr{ public static void main(String[] args){ Rad r1 = new Rad(); // Klasse Rad unbekannt ... } (4) ERROR: Class Rad not found. Innere Klassen in Java ... Eigenschaften Compilation: AutoTest.class, Auto.class, Auto$Rad.class Compilation innerer Klassen zu top-level Klassen unter Hinzufügung einer Instanz-Variable für die aktuellen Werte der umschließenden Klasse (5) Damit sind innere Klassen (bisher) nur eine syntaktische Erweiterung der Sprache Java, aber nicht der Plattform selbst! class Auto$Rad{ private Auto this$0; // speichert Kopie von Auto.this } Innere Klassen in Java Innere Klassen in Java (6) Vorteile von Inneren Klassen Aufnahme des code as data Konzepts aus der funktionalen Programmierung Realisierung von “method pointers”: Senden von Stücken von Code von einem Objekt zu einem anderen, wobei dieser Code Zugriff auf Felder des sendenden Objekts hat Bessere Strukturierung des Codes ähnlich der Idee von nested functions (z. B. in der funktionalen Programmierung); ABER: gilt hier nicht nur für Methoden, sondern für ganze Objekte Keine Sichtbarkeit nach Außen name space eines package wird nicht “vollgemüllt” ... Vorteile von Inneren Klassen Beispiel: Ereignisbezogene Programmierung, Benutzer-Schnittstellen Programmierung mit Java’s AWT } class Counter{ int x; class Listener implements ActionListener{ public void actionPerformed(ActionEvent e){x++;} } void listenTo(Button b){ b.addActionListener(new Listener()); } Innere Klassen in Java (7) Das erzeugte Objekt Button inkremetiert den Zähler immer wenn es gedrückt wird Methode listenTo erzeugt ein neues Listener Objekt und sendet es zu einem gegebenen Objekt der Klasse Button Methode der inneren Klasse Listener manipuliert Feld x der umschließenden Klasse Counter Counter c = new Counter(); Button b = new Button(‘‘Press me’’); c.listenTo(b); gui.add(b); Anwendungsmöglichkeiten Für die ereignisbezogene Programmierung (Beispiel Listener) Erzeugung von Adapter-Klassen: z. B. StackEnumeration, ListEnumeration als Adapter innerhalb einer Klasse Stack/List Definition abstrakter Datentypen (Liste, Stack): Listen-/Stack-Elemente als innere Klassen (siehe Vorlesung “Informatik I”, Skript Kapitel 9) Wissensrepräsentation: Schemahierarchien, verschachtelte strukturierte Objekte (Beispiel Auto) (8) Realisierung von Closures: Funktionen, die ihren lexikalischen Kontext erinnern und ihre freien Variablen darüber binden (funktionale Programmierung) Innere Klassen in Java ... Anwendungsmöglichkeiten Beispiel: Closures in Common Lisp [1]> (defun adder (n) (function (lambda (m) (+ m n)))) ADDER [2]> (setq add3 (adder 3)) #<CLOSURE :LAMBDA (M) (+ M N)> [3]> (funcall add3 4) 7 Für die innere, namenlose Funktion ist n eine freie Variable (9) Ergebnis von (adder 3) ist eine Funktion, die die Zahl 3 zu ihrem Argument (m) addiert Innere Klassen in Java Varianten Innerer Klassen Bisher: “echte” innere Klassen als member der umschließenden Klasse weitere Möglichkeiten – nested top-level Klassen (static innere Klasse) – lokale Klassen (innerhalb einer Methode) (10) – anonyme Klassen (namenlose lokale Klassen) Innere Klassen in Java ... Varianten Innerer Klassen Nested Top-Level Klassen } public class AdderN{ static class Add3{ int add(int m){ return m+3; } } public static void main(String[] args){ Add3 add3 = new Add3(); System.out.println(add3.add(4)); } Behandelt wie top-level Klassen (keine echten inneren Klassen) Vorteil: package-ähnliche Organisation für Klassen in einer Datei (11) Zugriff auf alle (privaten) Felder Innere Klassen in Java Lokale Klassen } ... Varianten Innerer Klassen public class AdderL{ public static void main(String[] args){ class Add3{ int add(int m){ return m+3; } } Add3 add3 = new Add3(); System.out.println(add3.add(4)); } Klasse innerhalb eines Blocks (einer Methode) Zugriff auf Namen wie jeder andere Ausdruck im Block Greift eine lokale Klasse auf (Instanz-) Variablen der umschließenden Klasse zu, so müssen diese in der lokalen Klasse final sein! (12) Auch nachdem die Methode verlassen wurde, bleiben solche Variablen für das innere Objekt verfügbar Innere Klassen in Java Anonyme Klassen interface Adder{ int add(int m); } } ... Varianten Innerer Klassen public class AdderA{ public static void main(String[] args){ Adder add3 = new Adder(){ public int add(int m){ return m+3; } }; System.out.println(add3.add(4)); } Spezialfall einer lokalen Klasse; für kleine selbsterklärende Stücke Code Kurzschreibweise für lokale Objekte Eine new Anweisung kann mit einem Klassen-Körper enden (13) Da namenlos: keine Konstruktoren! Innere Klassen in Java } Probleme mit Inneren Klassen Compiliert mit JDK 1.1.7: I’m a C.D object, compiliert mit JDK 1.2.2: I’m a C object Unklare Beziehung zwischen inneren Klassen und Vererbung (14) Möglicherweise sollten die derzeit existierenden Freiheitsgrade eingeschränkt werden (saubere Semantik!) Innere Klassen in Java Qualified this: Für eine innere Klasse C1.C2...Ci...Cn denotiert Ci.this die (n-i)-te direkt umschließende Instanz; aber was ist, wenn Ci Superklasse von Cn ist? 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(); } Java TM Tutorial: Literatur http://java.sun.com/docs/books/tutorial/post1.0/whatsnew/inner.html http://java.sun.com/docs/books/tutorial/java/javaOO/innerclasses.html Spezifikation Innerer Klassen von Sun: http://java.sun.com/products/jdk/1.1/docs/guide/innerclasses/index.html Chuck McManis (1997). Java In Depth: A look at inner classes, JavaWorld, 2(1). http://www.javaworld.com/javaworld/jw-10- 1997/jw- 10-indepth.html Brent W. Benson (1999). Java Reflections: Inner Classes: Closures for the Masses. ACM SIG-PLAN Notices, 34(2), 32-35. (15) Atsushi Igarashi and Benjamin C. Pierce (to appear). On inner classes. Information and Control. http://www.graco.c.u-tokyo.ac.jp/˜igarashi/papers/ecoop00.html Innere Klassen in Java