javaseiten.de   |   Version 0.6
 

1.10. Eingebettete Klassen

Innerhalb von Klassen können weitere Klassen deklariert werden. Sie werden als eingebettete Klassen (engl. nested classes) bezeichnet. Eingebettete Klassen können statische und nicht-statische Klassen sein. Engebettete Klassen, die mit dem Modifier static deklariert wurden, werden als statische eingebettete Klassen bezeichnet. Für eine nicht-statische eingebettete Klasse wird auch der Begriff innere Klasse verwendet. Die Klasse OuterClass enthält z.B. die zwei genannten Arten von eingebetteten Klassen: Eine statische eingebettete Klasse StaticNestedClass und eine innere Klasse InnerClass.

public class OuterClass {
  ...
  public static class StaticNestedClass {
    ...
  }
  public class InnerClass {
    ...
  }
  ...
}

1.10.1. Statische eingebettete Klassen

Das folgende Listing definiert die Klasse NestedClassExample. Im Klassenkörper dieser äußeren Klasse ist die statische eingebettete Klasse StaticNestedClass deklariert. Die eingebettete Klasse wird als Mitglied (member class) der äußeren Klasse angesehen. Im Beispiel wird das Feld a2 der eingebetteten Klasse mit Hilfe der Klassenvariablen a der äußeren Klasse initialisiert.

Listing 1.39. NestedClassExample.java. Beispiel zu statischen eingebetteten Klassen.

/* NestedClassExample.java */

public class NestedClassExample {
  
  static int a = 3;

  public static class StaticNestedClass {
    static int a2 = a;
    int b = 4;
    
    public static void method1() {
      System.out.println("Hello");
    }
    public void method2() {
      System.out.println("World!");
    }
  }
  
  public static void main(String[] args) {
    int a3 = NestedClassExample.StaticNestedClass.a2;
    System.out.println(a3);
    
    NestedClassExample.StaticNestedClass.method1();
    
    NestedClassExample.StaticNestedClass snc =
        new NestedClassExample.StaticNestedClass();
    int b2 = snc.b;
    System.out.println(b2);
    snc.method2();
  }
}

Der Java-Quelltext kann nun mit Hilfe von javac compiliert werden. Diese Übersetzung der Datei NestedClassExample.java führt in diesem Fall zur Generierung von insgesamt zwei Klassendateien: NestedClassExample.class und NestedClassExample$StaticNestedClass.class.

> javac NestedClassExample.java

--> NestedClassExample.class
    NestedClassExample$StaticNestedClass.class

Die Deklaration der eingebetteten Klasse erzwingt die Erzeugung einer zusätzlichen Klassendatei. Der Name dieser zweiten Klassendatei besteht aus drei Teilen. Er beginnt mit dem Namen der umschließenden Klasse, dem im Anschluss das Zeichen "$" folgt. Nach diesem Trennzeichen ist der Name der eingebetteten Klasse notiert. Durch das Beispiel zeigt sich, dass statische eingebettete Klassen in separate Klassendateien ausgelagert werden. Wird das Beispiel nun ausgeführt, kann eine Bildschirmausgabe erzeugt werden:

> java NestedClassExample

3
Hello
4
World!

Innerhalb der main-Methode des Beispiels erfolgt zunächst der Zugriff auf das Feld a2 und der Aufruf der statischen Methode method1. Das Feld und die genannte Methode befinden sich innerhalb der eingebetteten Klasse. Um diese zu adressieren, wird ebenfalls eine Punktnotation verwendet, wobei der Name der statischen eingebetteten Klasse zwischen dem Namen der äußeren Klasse und dem Feldnamen (Methodennamen) notiert ist. Von einer statischen eingebetteten Klasse kann ein Objekt erzeugt werden, um das nicht-statische Feld b bzw. die nicht-statische Methode method2 anzusprechen. Die folgende Übersicht enthält einen Eintrag zu dieser Objekterzeugung:

Zugriff auf statische Felder:
    KlassenName1.KlassenName2.FeldName

Aufruf von statischen Methoden:
    KlassenName1.KlassenName2.MethodenName

Erzeugung eines Objekts:
    KlassenName1.KlassenName2 obj = new KlassenName1.KlassenName2();

(Äußere Klasse: KlassenName1, statische eingebettete Klasse: KlassenName2)

1.10.2. Innere Klassen

Eine eingebettete Klasse, die nicht mit dem Modifier static deklariert wurde, wird als innere Klasse bezeichnet. Die Menge der inneren Klassen kann in drei Bereiche unterteilt werden: Nicht-statische Member-Klassen, lokale (innere) Klassen und anonyme (innere) Klassen. Die unterschiedlichen Arten von inneren Klassen sollen in den folgenden Abschnitten beschrieben werden.

1.10.2.1. Nicht-statische Member-Klassen

Eine nicht-statische Member-Klasse ist ein Klasse, deren Deklaration direkt von einer äußeren Klasse umschlossen wird. Das folgende kurze Beispiel definiert die Klasse NestedClassExample2, deren Körper neben zwei Methoden auch die nicht-statische Member-Klasse InnerClass enthält. Sie beinhaltet ein nicht-statisches Feld und eine nicht-statische Methode. Die innere Klasse kann keine statischen Felder und keine statischen Methoden deklarieren. Die Verwendung statischer Deklarationen würde der Compiler mit einer Fehlermeldung quittieren ("inner classes cannot have static declarations").

Listing 1.40. NestedClassExample2.java. Beispiel zu inneren Klassen (nicht-statische Member-Klasse).

/* NestedClassExample2.java */

public class NestedClassExample2 {
  
  public class InnerClass {
    int b = 4;
        
    public void method2() {
      System.out.println("World!");
    }
  }
  
  public void method1() {
    InnerClass ic = new InnerClass();
    System.out.println(ic.b);
  }
  
  public static void main(String[] args) {
    NestedClassExample2 nce2 = new NestedClassExample2();
    nce2.method1();
    
    NestedClassExample2.InnerClass ic2 = nce2. new InnerClass();
    System.out.println(ic2.b);
    ic2.method2();
  }
}

Die Compilierung von NestedClassExample2.java führt zur Erzeugung der beiden Klassendateien NestedClassExample2.class und NestedClassExample2$InnerClass.class. Nach Ausführen des Beispiels werden auf dem Bildschirm drei Zeilen mit den Inhalten "4", "4", und "World!" ausgegeben. Die erste "4" wird durch den Aufruf von method1 ausgegeben. Innerhalb dieser Methode wird zunächst ein Objekt der inneren Klasse beschafft, damit mit Hilfe der Punktnoation auf das Feld b zugegriffen werden kann. Die zweite ausgegebene "4" beruht auf Anweisungen innerhalb der main-Methode, die erläutert werden sollen: Die Erzeugung von Objekten kann mit Hilfe einer qualifizierten Objekterzeugung erfolgen. Durch diese wird die Möglichkeit geschaffen, Objekte einer inneren Klasse zu generieren. Bei dieser Form der Objekterzeugung wird vor dem Schlüsselwort new ein Primary notiert. Die Abgrenzung zwischen dem Primary und new erfolgt durch einen Punkt. Die Primary-Angabe ist notwendig, da die Erzeugung eines Objekts einer inneren Klasse ein vorhandenes Objekt der äußeren Klasse (im Beispiel nce2) voraussetzt.

Primary. new KlassenName(ArgumentListe_opt)

(Qualifizierte Objekterzeugung (vereinfacht),
"qualified class instance creation expression")

1.10.2.2. Lokale Klassen

Eine Klasse kann auch innerhalb eines Methodenkörpers deklariert werden. Derartige Klassen werden als lokale Klassen bezeichnet. Die Verwendung der Modifier public, protected, private und static bei der Deklaration einer lokalen Klasse ist nicht zugelassen und würde zu einer Fehlermeldung während der Compilierung führen. Das Beispiel zu lokalen Klassen NestedClassExample3.java deklariert zwei Methoden, wobei innerhalb des Körpers von method1 die lokale Klasse LocalClass deklariert ist.

Listing 1.41. NestedClassExample3.java. Beispiel zu lokalen (inneren) Klassen.

/* NestedClassExample3.java */

public class NestedClassExample3 {
  
  public void method1() {
    final int b = 4;
    
    class LocalClass {
      int b2 = b;
      public void method2() {
        System.out.println("World!");
      }
    }
    
    LocalClass lc = new LocalClass();
    System.out.println(lc.b2);
    lc.method2();
  }
  
  public static void main(String[] args) {
    NestedClassExample3 nce3 = new NestedClassExample3();
    nce3.method1();
  }
}

Die Abarbeitung des Programms führt zur Ausgabe von "4" und "World!". Das Feld b2 der lokalen Klasse wird mit Hilfe des Feldes b initialisiert. Dies ist nur möglich, da b mit final deklariert wurde. Die lokale Klasse wird innerhalb der Methode method1 genutzt, indem von dieser ein Objekt erzeugt wird.

1.10.2.3. Anonyme Klassen

Die Deklaration einer anonymen Klasse erfolgt durch eine Class-Instance-Creation-Expression. Die Instanzierung und Deklaration der anonymen Klasse erfolgt dadurch in einem Schritt.

Erweiterung der Klasse KlassenName:
    new KlassenName()
    {
      ...
    }

Implementierung des Interfaces InterfaceName:
    new InterfaceName()
    {
      ...
    }

Die zu deklarierende anonyme Klasse (innerhalb des geschweiften Klammerpaares) kann eine vorhandene Klasse erweitern oder ein Interface implementieren. Handelt es sich nach dem Schlüsselwort new um einen Klassennamen, dann wird die entsprechende Klasse durch die zu erstellende anonyme Klasse erweitert. Im zweiten Fall muss die anonyme Klasse das hinter new angegebene Interface implementieren. Das folgende Listing definiert eine Klasse, die später durch eine anonyme Klasse erweitert werden soll:

Listing 1.42. AnonymousSuperClass.java. Superklasse der anonymen Klasse aus Listing 1.43.

/* AnonymousSuperClass.java */

public abstract class AnonymousSuperClass {
  int a = 3;
  public abstract int method2();
}

Der Java-Quelltext NestedClassExample4.java verwendet die abstrakte Klasse AnonymousSuperClass. Innerhalb der main-Methode wird method1 aufgerufen, wobei eine Instanz einer anonymen Klasse übergeben wird. Die anonyme Klasse erweitert die abstrakte Klasse AnonymousSuperClass. Dazu wird deren abstakte Methode method2 implmentiert. Zusätzlich wird das Feld b deklariert.

Listing 1.43. NestedClassExample4.java. Beispiel zu anonymen (inneren) Klassen.

/* NestedClassExample4.java */

public class NestedClassExample4 {
  
  public void method1(AnonymousSuperClass asc) {
    int d = asc.method2();
    System.out.println(d);
  }
  
  public static void main(String[] args) {
    NestedClassExample4 nce4 = new NestedClassExample4();
    nce4.method1(new AnonymousSuperClass() {
                   int b = 4;
                   public int method2() {
                     int c = a * b;
                     return c;
                   }
                 }
                );
  }
}

Der einzige Parameter der Methode method1 ist vom Typ AnonymousSuperClass (die an die Methode übergebene Instanz ist eine Instanz einer Subklasse von AnonymousSuperClass). Innerhalb von method1 wird nun der erhaltene Parameter dazu verwendet, um die Methode method2 der anonymen Klasse aufzurufen. Die Methode gibt den Zahlenwert 12 zurück.

 

 

 

Diese Seite nutzt Google-Dienste - siehe dazu Datenschutz.

Copyright © 2006, 2007 Harald Roeder