CodeGym /Java-Blog /Random-DE /Verschachtelte innere Klassen
Autor
John Selawsky
Senior Java Developer and Tutor at LearningTree

Verschachtelte innere Klassen

Veröffentlicht in der Gruppe Random-DE
Hallo! Heute befassen wir uns mit einem wichtigen Thema – der Funktionsweise verschachtelter Klassen in Java. Mit Java können Sie Klassen innerhalb einer anderen Klasse erstellen:

class OuterClass {
    ...
    static class StaticNestedClass {
        ...
    }
    class InnerClass {
        ...
    }
}
Diese internen Klassen werden als verschachtelt bezeichnet. Sie sind in 2 Typen unterteilt:
  1. Nicht statische verschachtelte Klassen. Diese werden auch innere Klassen genannt.
  2. Statisch verschachtelte Klassen.
Innere Klassen wiederum haben zwei unterschiedliche Unterkategorien. Zusätzlich dazu, dass eine innere Klasse einfach eine innere Klasse ist, kann sie auch Folgendes sein:
  • eine lokale Klasse
  • eine anonyme Klasse
Verwirrt? :) Das ist okay. Hier ist ein Diagramm zur Verdeutlichung. Kommen Sie während des Unterrichts darauf zurück, wenn Sie plötzlich verwirrt sind! Verschachtelte innere Klassen – 2In der heutigen Lektion besprechen wir innere Klassen (auch als nicht statische verschachtelte Klassen bekannt). Sie sind im Gesamtdiagramm besonders hervorgehoben, damit Sie sich nicht verlaufen :) Beginnen wir mit der offensichtlichen Frage: Warum werden sie „innere“ Klassen genannt? Die Antwort ist ganz einfach: weil sie innerhalb anderer Klassen erstellt werden. Hier ist ein Beispiel:

public class Bicycle {

   private String model;
   private int weight;

   public Bicycle(String model, int weight) {
       this.model = model;
       this.weight = weight;
   }
  
   public void start() {
       System.out.println("Let's go!");
   }

   public class Handlebar {

       public void right() {
           System.out.println("Steer right!");
       }

       public void left() {

           System.out.println("Steer left!");
       }
   }

   public class Seat {
      
       public void up() {

           System.out.println("Seat up!");
       }
      
       public void down() {

           System.out.println("Seat down!");
       }
   }
}
Hier haben wir die BicycleKlasse. Es hat 2 Felder und 1 Methode: start(). Verschachtelte innere Klassen – 3Sie unterscheidet sich von einer gewöhnlichen Klasse dadurch, dass sie zwei Klassen enthält: Handlebarund Seat. Ihr Code wird innerhalb der BicycleKlasse geschrieben. Dabei handelt es sich um vollwertige Klassen: Wie Sie sehen, hat jede von ihnen ihre eigenen Methoden. An diesem Punkt haben Sie vielleicht eine Frage: Warum in aller Welt sollten wir eine Klasse in eine andere einordnen? Warum sie zu inneren Klassen machen? Angenommen, wir benötigen in unserem Programm separate Klassen für die Konzepte Lenker und Sitz. Natürlich ist es für uns nicht notwendig, sie zu verschachteln! Wir können normale Kurse machen. Zum Beispiel so:

public class Handlebar {
   public void right() {
       System.out.println("Steer right!");
   }

   public void left() {

       System.out.println("Steer left");
   }
}

public class Seat {

   public void up() {

       System.out.println("Seat up!");
   }

   public void down() {

       System.out.println("Seat down!");
   }
}
Sehr gute Frage! Natürlich sind wir nicht durch die Technologie eingeschränkt. Das ist sicherlich eine Option. Hier kommt es vielmehr auf die richtige Gestaltung der Kurse im Hinblick auf ein bestimmtes Programm und dessen Zweck an. Innere Klassen dienen dazu, eine Entität abzutrennen, die untrennbar mit einer anderen Entität verbunden ist. Lenker, Sitze und Pedale sind Bestandteile eines Fahrrads. Getrennt vom Fahrrad machen sie wenig Sinn. Wenn wir alle diese Konzepte zu separaten öffentlichen Klassen gemacht hätten, hätten wir den folgenden Code in unserem Programm gehabt:

public class Main {

   public static void main(String[] args) {
       Handlebar handlebar = new Handlebar();
       handlebar.right();
   }
}
Hmm ... Die Bedeutung dieses Codes ist sogar schwer zu erklären. Wir haben einen vagen Lenker (Warum ist er notwendig? Keine Ahnung, um ehrlich zu sein). Und dieser Griff dreht sich nach rechts... ganz von alleine, ohne Fahrrad... aus irgendeinem Grund. Durch die Trennung des Konzepts des Lenkers vom Konzept des Fahrrads haben wir in unserem Programm etwas an Logik verloren. Bei Verwendung einer inneren Klasse sieht der Code ganz anders aus:

public class Main {

   public static void main(String[] args) {

       Bicycle peugeot = new Bicycle("Peugeot", 120);
       Bicycle.Handlebar handlebar = peugeot.new Handlebar();
       Bicycle.Seat seat = peugeot.new Seat();

       seat.up();
       peugeot.start();
       handlebar.left();
       handlebar.right();
   }
}
Konsolenausgabe:

Seat up! 
Let's go! 
Steer left! 
Steer right!
Jetzt macht das, was wir sehen, plötzlich Sinn! :) Wir haben ein Fahrradobjekt erstellt. Wir haben zwei Fahrrad-„Unterobjekte“ erstellt – einen Lenker und einen Sitz. Wir stellten den Sitz hoch, um es bequemer zu machen, und los ging es: Treten und lenken Sie nach Bedarf! :) Die von uns benötigten Methoden werden für die entsprechenden Objekte aufgerufen. Es ist alles einfach und bequem. In diesem Beispiel verbessert die Trennung von Lenker und Sitz die Kapselung (wir verbergen Daten zu den Fahrradteilen innerhalb der relevanten Klasse) und ermöglicht uns die Erstellung einer detaillierteren Abstraktion. Schauen wir uns nun eine andere Situation an. Angenommen, wir möchten ein Programm erstellen, das einen Fahrradladen und Ersatzteile für Fahrräder simuliert. Verschachtelte innere Klassen – 4In dieser Situation wird unsere vorherige Lösung nicht funktionieren. In einem Fahrradladen macht jedes einzelne Fahrradteil auch getrennt vom Fahrrad Sinn. Wir benötigen beispielsweise Methoden wie „Pedale an einen Kunden verkaufen“, „einen neuen Sitz kaufen“ usw. Es wäre ein Fehler, hier innere Klassen zu verwenden – jedes einzelne Fahrradteil in unserem neuen Programm hat eine Bedeutung, die Bestand hat sein eigenes: Es kann vom Konzept eines Fahrrads getrennt werden. Genau darauf müssen Sie achten, wenn Sie sich fragen, ob Sie innere Klassen verwenden oder alle Entitäten als separate Klassen organisieren sollten. Der Vorteil der objektorientierten Programmierung liegt darin, dass sie die Modellierung realer Entitäten vereinfacht. Dies kann Ihr Leitprinzip sein, wenn Sie entscheiden, ob Sie innere Klassen verwenden. In einem echten Geschäft, Ersatzteile sind von Fahrrädern getrennt – das ist in Ordnung. Dies bedeutet, dass es auch beim Entwerfen eines Programms in Ordnung ist. Okay, wir haben die „Philosophie“ herausgefunden :) Machen wir uns nun mit wichtigen „technischen“ Merkmalen innerer Klassen vertraut. Folgendes müssen Sie unbedingt beachten und verstehen:
  1. Ein Objekt einer inneren Klasse kann nicht ohne ein Objekt einer äußeren Klasse existieren.

    Das macht Sinn: Aus diesem Grund haben wir die Seatund Handlebarinneren Klassen in unser Programm aufgenommen – damit wir nicht mit verwaisten Lenkern und Sitzen enden.

    Dieser Code lässt sich nicht kompilieren:

    
    public static void main(String[] args) {
    
       Handlebar handlebar = new Handlebar();
    }
    

    Daraus ergibt sich ein weiteres wichtiges Merkmal:

  2. Ein Objekt einer inneren Klasse hat Zugriff auf die Variablen der äußeren Klasse.

    Fügen wir unserer Klasse beispielsweise eine int seatPostDiameterVariable hinzu (die den Durchmesser der Sattelstütze darstellt) Bicycle.

    Dann Seatkönnen wir in der inneren Klasse eine Methode erstellen, displaySeatProperties()die die Sitzeigenschaften anzeigt:

    
    public class Bicycle {
    
       private String model;
       private int weight;
    
       private int seatPostDiameter;
    
       public Bicycle(String model, int weight, int seatPostDiameter) {
           this.model = model;
           this.weight = weight;
           this.seatPostDiameter = seatPostDiameter;
    
       }
    
       public void start() {
           System.out.println("Let's go!");
       }
    
       public class Seat {
    
           public void up() {
    
               System.out.println("Seat up!");
           }
    
           public void down() {
    
               System.out.println("Seat down!");
           }
    
           public void displaySeatProperties() {
    
               System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter);
           }
       }
    }
    

    Und jetzt können wir diese Informationen in unserem Programm anzeigen:

    
    public class Main {
    
       public static void main(String[] args) {
    
           Bicycle bicycle = new Bicycle("Peugeot", 120, 40);
           Bicycle.Seat seat = bicycle.new Seat();
    
           seat.displaySeatProperties();
       }
    }
    

    Konsolenausgabe:

    
    Seat properties: seatpost diameter = 40
    

    Notiz:Die neue Variable wird mit dem strengsten Zugriffsmodifikator ( private) deklariert. Und trotzdem hat die innere Klasse Zugriff!

  3. Ein Objekt einer inneren Klasse kann nicht in einer statischen Methode einer äußeren Klasse erstellt werden.

    Dies erklärt sich aus den Besonderheiten der Organisation innerer Klassen. Eine innere Klasse kann Konstruktoren mit Parametern oder nur den Standardkonstruktor haben. Unabhängig davon wird jedoch beim Erstellen eines Objekts einer inneren Klasse unsichtbar ein Verweis auf das Objekt der äußeren Klasse an das erstellte Objekt der inneren Klasse übergeben. Schließlich ist das Vorhandensein einer solchen Objektreferenz zwingend erforderlich. Andernfalls können wir keine Objekte der inneren Klasse erstellen.

    Aber wenn eine Methode der äußeren Klasse statisch ist, dann haben wir möglicherweise kein Objekt der äußeren Klasse! Und dies wäre ein Verstoß gegen die Logik, wie eine innere Klasse funktioniert. In dieser Situation generiert der Compiler einen Fehler:

    
    public static Seat createSeat() {
      
       // Bicycle.this cannot be referenced from a static context
       return new Seat();
    }
    
  4. Eine innere Klasse kann keine statischen Variablen und Methoden enthalten.

    Die Logik ist dieselbe: Statische Methoden und Variablen können auch dann existieren und aufgerufen oder referenziert werden, wenn kein Objekt vorhanden ist.

    Aber ohne ein Objekt der äußeren Klasse haben wir keinen Zugriff auf die innere Klasse.

    Ein klarer Widerspruch! Aus diesem Grund sind statische Variablen und Methoden in inneren Klassen nicht zulässig.

    Der Compiler generiert einen Fehler, wenn Sie versuchen, sie zu erstellen:

    
    public class Bicycle {
    
       private int weight;
    
    
       public class Seat {
          
           // An inner class cannot have static declarations
           public static void displaySeatProperties() {
    
               System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter);
           }
       }
    }
    
  5. Beim Erstellen eines Objekts einer inneren Klasse ist sein Zugriffsmodifikator wichtig.

    Eine innere Klasse kann mit den Standardzugriffsmodifikatoren , public, privateund protectedmarkiert werden package private.

    Warum ist das wichtig?

    Dies wirkt sich darauf aus, wo wir in unserem Programm Instanzen der inneren Klasse erstellen können.

    Wenn unsere SeatKlasse als deklariert ist public, können wir SeatObjekte in jeder anderen Klasse erstellen. Die einzige Voraussetzung ist, dass auch ein Objekt der äußeren Klasse vorhanden sein muss.

    Das haben wir hier übrigens schon gemacht:

    
    public class Main {
    
       public static void main(String[] args) {
    
           Bicycle peugeot = new Bicycle("Peugeot", 120);
           Bicycle.Handlebar handlebar = peugeot.new Handlebar();
           Bicycle.Seat seat = peugeot.new Seat();
    
           seat.up();
           peugeot.start();
           handlebar.left();
           handlebar.right();
       }
    }
    

    Von der Klasse aus haben wir leicht Zugang zur Handlebarinneren Klasse erhalten Main.

    Wenn wir die innere Klasse als deklarieren private, können wir Objekte nur innerhalb der äußeren Klasse erstellen.

    Wir können kein SeatObjekt mehr „außen“ erstellen:

    
    private class Seat {
    
       // Methods
    }
    
    public class Main {
    
       public static void main(String[] args) {
    
           Bicycle bicycle = new Bicycle("Peugeot", 120, 40);
    
           // Bicycle.Seat has private access in Bicycle
           Bicycle.Seat seat = bicycle.new Seat();
       }
    }
    

    Du verstehst die Logik wahrscheinlich schon :)

  6. Zugriffsmodifikatoren für innere Klassen funktionieren genauso wie für gewöhnliche Variablen.

    Der protectedModifikator ermöglicht den Zugriff auf eine Instanzvariable in Unterklassen und Klassen, die sich im selben Paket befinden.

    protectedFunktioniert auch für innere Klassen. protectedWir können Objekte der inneren Klasse erstellen :

    • in der äußeren Klasse;
    • in seinen Unterklassen;
    • in Klassen, die sich im selben Paket befinden.

    Wenn die innere Klasse keinen Zugriffsmodifikator ( package private) hat, können Objekte der inneren Klasse erstellt werden:

    • in der äußeren Klasse;
    • in Klassen, die sich im selben Paket befinden.

    Mit Modifikatoren sind Sie schon lange vertraut, daher gibt es hier keine Probleme.

Das ist alles für den Moment :) Aber lassen Sie nicht nach! Innere Klassen sind ein ziemlich umfangreiches Thema, das wir in der nächsten Lektion weiter untersuchen werden. Jetzt können Sie Ihre Erinnerung an die Lektion unseres Kurses über innere Klassen auffrischen . Und das nächste Mal sprechen wir über statisch verschachtelte Klassen.
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION