JavaRush /Java-Blog /Random-DE /Verschachtelte innere Klassen oder innere Klasse in Java

Verschachtelte innere Klassen oder innere Klasse in Java

Veröffentlicht in der Gruppe Random-DE
Hallo! Heute beginnen wir mit der Betrachtung eines wichtigen Themas – wie verschachtelte Klassen in Java funktionieren. Im Englischen werden sie verschachtelte Klassen genannt. Mit Java können Sie einige Klassen innerhalb anderer erstellen:
class OuterClass {
    ...
    static class StaticNestedClass {
        ...
    }
    class InnerClass {
        ...
    }
}
Es sind diese Klassen, die als verschachtelt bezeichnet werden. Sie sind in 2 Typen unterteilt:
  1. Nicht statisch verschachtelte Klassen – nicht statisch verschachtelte Klassen. Sie werden auf andere Weise auch innere Klassen genannt.
  2. Statisch verschachtelte Klassen – statisch verschachtelte Klassen.
Innere Klassen haben wiederum zwei spezielle Untertypen. Neben der Tatsache, dass eine innere Klasse nur eine innere Klasse sein kann, kann sie auch sein:
  • lokale Klasse
  • anonyme Klasse
Etwas schwierig? :) Es ist in Ordnung, hier ist ein Diagramm zur Verdeutlichung. Kommen Sie während der Vorlesung noch einmal darauf zurück, wenn Sie plötzlich verwirrt sind! Verschachtelte innere Klassen – 2In der heutigen Vorlesung werden wir über innere Klassen sprechen – interne Klassen (sie sind auch nicht statische verschachtelte Klassen, nicht statische verschachtelte Klassen). Sie sind im allgemeinen Diagramm besonders hervorgehoben, damit Sie sich nicht verlaufen :) Beginnen wir mit der offensichtlichen Frage: Warum werden diese Klassen „intern“ 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("Gehen!");
   }

   public class HandleBar {

       public void right() {
           System.out.println(„Lenkrad nach rechts!“);
       }

       public void left() {

           System.out.println(„Lenkrad nach links!“);
       }
   }

   public class Seat {

       public void up() {

           System.out.println(„Der Sitz ist oben!“);
       }

       public void down() {

           System.out.println(„Der Sitz ist unten!“);
       }
   }
}
Hier haben wir eine Klasse Bicycle– Fahrrad. Es hat 2 Felder und 1 Methode - start(). Verschachtelte innere Klassen – 3Der Unterschied zu einer regulären Klasse besteht darin, dass sie zwei Klassen hat, deren Code darin geschrieben ist Bicycle– dies sind die Klassen HandleBar(Lenkrad) und Seat(Sitz). Dabei handelt es sich um vollwertige Klassen: Wie Sie sehen, hat jede von ihnen ihre eigenen Methoden. An dieser Stelle haben Sie möglicherweise eine Frage: Warum haben wir eine Klasse in eine andere eingefügt? Warum sie intern machen? Okay, nehmen wir an, wir brauchen im Programm separate Klassen für Lenkrad und Sitz. Aber Sie müssen sie nicht verschachteln! Sie können reguläre Kurse machen. Zum Beispiel so:
public class HandleBar {
   public void right() {
       System.out.println(„Lenkrad nach rechts!“);
   }

   public void left() {

       System.out.println(„Lenkrad links“);
   }
}

public class Seat {

   public void up() {

       System.out.println(„Der Sitz ist oben!“);
   }

   public void down() {

       System.out.println(„Der Sitz ist unten!“);
   }
}
Sehr gute Frage! Natürlich haben wir keine technischen Einschränkungen – wir können es so machen. Es geht vielmehr darum, Klassen aus der Sicht eines bestimmten Programms und im Sinne dieses Programms richtig zu gestalten. Innere Klassen sind Klassen zum Hervorheben einer bestimmten Entität in einem Programm, die untrennbar mit einer anderen Entität verbunden ist. Lenkrad, Sitz, Pedale sind die Bestandteile eines Fahrrades. Getrennt vom Fahrrad machen sie keinen Sinn. Wenn wir alle diese Klassen zu separaten öffentlichen Klassen machen würden, könnte unser Programm beispielsweise den folgenden Code haben:
public class Main {

   public static void main(String[] args) {
       HandleBar handleBar = new HandleBar();
       handleBar.right();
   }
}
Ähm... Die Bedeutung dieses Codes ist sogar schwer zu erklären. Wir haben einen seltsamen Fahrradlenker (warum wird er benötigt? Ehrlich gesagt keine Ahnung). Und dieses Lenkrad dreht sich nach rechts... von alleine, ohne Fahrrad... aus irgendeinem Grund. Durch die Trennung der Essenz des Lenkrads von der Essenz des Fahrrads haben wir die Logik unseres Programms verloren. Bei Verwendung einer inneren Klasse sieht der Code völlig 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:

Сиденье поднято выше!
Поехали!
Руль влево!
Руль вправо!
Was geschah, ergab plötzlich einen Sinn! :) Wir haben ein Fahrradobjekt erstellt. Wir haben zwei seiner „Unterobjekte“ erstellt – das Lenkrad und den Sitz. Der Bequemlichkeit halber haben wir den Sitz höher gestellt – und schon ging es los: Wir rollen und lenken dorthin, wo wir hin müssen! :) Die von uns benötigten Methoden werden für die erforderlichen Objekte aufgerufen. Alles ist einfach und bequem. In diesem Beispiel verbessert die Hervorhebung des Lenkers und des Sitzes die Kapselung (wir verbergen Daten über die Teile des Fahrrads innerhalb der entsprechenden Klasse) und ermöglicht uns die Erstellung einer detaillierteren Abstraktion. Schauen wir uns nun eine andere Situation an. Nehmen wir an, wir möchten ein Programm erstellen, das ein Fahrrad- und Teilegeschäft modelliert. Verschachtelte innere Klassen – 4In dieser Situation wird unsere bisherige Lösung scheitern. Innerhalb eines Teilelagers hat jedes einzelne Teil eines Fahrrads eine Bedeutung, auch außerhalb des Wesens des Fahrrads. Wir benötigen beispielsweise Methoden wie „Pedale an einen Käufer verkaufen“, „Neuen Sitz kaufen“ usw. Es wäre ein Fehler, hier interne Klassen zu verwenden – jeder einzelne Teil des Fahrrads in unserem neuen Programm hat seine eigene Bedeutung: Er ist vom Wesen des Fahrrads getrennt und in keiner Weise mit ihm verbunden. Darauf sollten Sie achten, wenn Sie sich fragen, ob Sie innere Klassen verwenden oder alle Entitäten in separate Klassen aufteilen müssen. Objektorientierte Programmierung ist großartig, weil sie die Modellierung realer Entitäten erleichtert. Dies können Sie als Leitfaden bei der Entscheidung verwenden, ob Sie innere Klassen verwenden möchten. In einem echten Geschäft sind die Teile getrennt von den Fahrrädern – das ist normal. Dies bedeutet, dass dies beim Entwerfen eines Programms korrekt ist. Okay, wir haben die „Philosophie“ geklärt :) Machen wir uns nun mit den 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 ist logisch: Deshalb haben wir es zu Seatinternen HandleBarKlassen gemacht, damit herrenlose Lenkräder und Sitze nicht hier und da in unserem Programm auftauchen.

    Dieser Code lässt sich nicht kompilieren:

    public static void main(String[] args) {
    
       HandleBar handleBar = new HandleBar();
    }

    Daraus ergibt sich folgendes wichtiges Merkmal:

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

    Fügen wir unserer Klasse beispielsweise Bicycleeine Variable hinzu int seatPostDiameter– den Durchmesser der Sattelstütze.

    SeatDann können wir in der inneren Klasse eine Methode erstellen getSeatParam(), die uns den Sitzparameter mitteilt:

    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("Gehen!");
       }
    
       public class Seat {
    
           public void up() {
    
               System.out.println(„Der Sitz ist oben!“);
           }
    
           public void down() {
    
               System.out.println(„Der Sitz ist unten!“);
           }
    
           public void getSeatParam() {
    
               System.out.println("Sattelparameter: Sattelstützendurchmesser = " + Bicycle.this.seatPostDiameter);
           }
       }
    }

    Und jetzt können wir diese Informationen in unser Programm aufnehmen:

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

    Konsolenausgabe:

    
    Параметр сиденья: диаметр подседельного штыря = 40

    Passt auf:Die neue Variable wird mit dem strengsten Modifikator deklariert – private. Und trotzdem hat die innere Klasse Zugriff!

  3. Ein inneres Klassenobjekt kann nicht in einer statischen Methode einer „äußeren“ Klasse erstellt werden.

    Dies wird durch die Designmerkmale interner Klassen erklärt. Eine innere Klasse kann Konstruktoren mit Parametern oder nur einen Standardkonstruktor haben. Aber unabhängig davon wird beim Erstellen eines Objekts der inneren Klasse stillschweigend ein Verweis auf ein Objekt der „äußeren“ Klasse an dieses übergeben. Schließlich ist die Anwesenheit eines solchen Objekts Voraussetzung. Andernfalls können wir keine Objekte der inneren Klasse erstellen.

    Wenn die Methode der äußeren Klasse jedoch statisch ist, existiert das Objekt der äußeren Klasse möglicherweise überhaupt nicht! Dies bedeutet, dass die Logik der inneren Klasse gebrochen wird. In einer solchen Situation gibt der Compiler einen Fehler aus:

    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 hier ist dieselbe: Statische Methoden und Variablen können existieren und aufgerufen werden, auch wenn kein Objekt vorhanden ist.

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

    Ein offensichtlicher Widerspruch! Daher ist das Vorhandensein statischer Variablen und Methoden in inneren Klassen verboten.

    Der Compiler gibt einen Fehler aus, wenn er versucht, sie zu erstellen:

    public class Bicycle {
    
       private int weight;
    
    
       public class Seat {
    
           //inner class cannot have static declarations
           public static void getSeatParam() {
    
               System.out.println("Sattelparameter: Sattelstützendurchmesser = " + Bicycle.this.seatPostDiameter);
           }
       }
    }
  5. Beim Erstellen eines Objekts einer inneren Klasse spielt sein Zugriffsmodifikator eine wichtige Rolle.

    Eine innere Klasse kann durch die Standardzugriffsmodifikatoren - public, und bezeichnet werden .privateprotectedpackage private

    Warum ist es wichtig?

    Dies wirkt sich darauf aus, wo in unserem Programm wir die innere Klasse instanziieren können.

    Wenn unsere Klasse Seatals deklariert ist public, können wir ihre Objekte in jeder anderen Klasse erstellen. Die einzige Voraussetzung ist, dass auch ein Objekt der „externen“ Klasse vorhanden sein muss.

    Das haben wir übrigens hier 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();
       }
    }

    HandleBarWir haben von der aus leicht auf die innere Klasse zugegriffen Main.

    Wenn wir die innere Klasse als deklarieren private, haben wir nur Zugriff auf die Erstellung von Objekten innerhalb der „äußeren“ Klasse.

    SeatWir können kein Objekt mehr von außen erstellen :

    private class Seat {
    
       //Methoden
    }
    
    public class Main {
    
       public static void main(String[] args) {
    
           Bicycle bicycle = new Bicycle("Peugeot", 120, 40);
    
           //Bicycle.Seat has a 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 reguläre Variablen.

    Der Modifikator protectedermöglicht den Zugriff auf eine Klassenvariable in ihren Nachkommenklassen und in Klassen, die sich im selben Paket befinden.

    Das Gleiche protectedgilt für innere Klassen. protectedInnere Klassenobjekte können erstellt werden:

    • innerhalb der „äußeren“ Klasse;
    • in seinen Nachkommenklassen;
    • in den Klassen, die im selben Paket enthalten sind.

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

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

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

Das ist alles für den Moment :) Aber entspannen Sie sich nicht! Interne verschachtelte Klassen sind ein ziemlich breites Thema, das wir in zukünftigen Lektionen weiter untersuchen werden. Jetzt können Sie die Vorlesung über interne Kurse aus unserem Kurs auffrischen . Und das nächste Mal werden wir über statisch verschachtelte Klassen sprechen.
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION