JavaRush /Java-Blog /Random-DE /Vererbung verschachtelter Klassen

Vererbung verschachtelter Klassen

Veröffentlicht in der Gruppe Random-DE
Hallo! Heute werden wir uns die Funktionsweise eines wichtigen Mechanismus ansehen – der Vererbung in verschachtelten Klassen. Ich weiß nicht, ob Sie jemals darüber nachgedacht haben, was Sie tun, wenn Sie eine verschachtelte Klasse von einer anderen erben müssen. Wenn nicht, glauben Sie mir: Diese Situation kann verwirrend sein, denn hier gibt es viele Nuancen:
  1. Erben wir eine verschachtelte Klasse von einer Klasse oder erben wir eine andere Klasse von einer verschachtelten Klasse?
  2. Ist der Nachfolger/die geerbte Klasse eine reguläre öffentliche Klasse oder handelt es sich auch um eine verschachtelte Klasse?
  3. Welche Art von verschachtelten Klassen verwenden wir schließlich genau in all diesen Situationen?
Wenn Sie alle diese Fragen beantworten, wird es so viele mögliche Antworten geben, dass Ihnen der Kopf schwirrt :) Wie Sie wissen, müssen Sie ein komplexes Problem in einfachere Teile zerlegen, um es zu lösen. Das werden wir tun. Schauen wir uns jede Gruppe verschachtelter Klassen der Reihe nach aus zwei Perspektiven an: Wer kann von dieser Art verschachtelter Klasse erben und von wem kann sie erben? Beginnen wir mit statisch verschachtelten Klassen.

Statisch verschachtelte Klassen

Beispiele für die Vererbung interner Klassen - 2Ihre Vererbungsregeln sind die einfachsten. Hier können Sie fast alles tun, was Ihr Herz begehrt. Eine statisch verschachtelte Klasse kann geerbt werden von:
  • Regelklasse
  • eine statisch verschachtelte Klasse, die in der äußeren Klasse oder ihren Vorgängern deklariert wird
Erinnern wir uns an das Beispiel aus der Vorlesung über statisch verschachtelte Klassen.
public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

       public static int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
Versuchen wir, den Code zu ändern und eine statische verschachtelte Klasse Drawingund ihren Nachkommen zu erstellen Boeing737Drawing.
public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

   }

   public static class Boeing737Drawing extends Drawing {

       public static int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
Wie Sie sehen, kein Problem. Wir können die Klasse ganz entfernen Drawingund sie zu einer regulären öffentlichen Klasse anstelle einer statisch verschachtelten Klasse machen – es wird sich nichts ändern.
public class Drawing {

}

public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Boeing737Drawing extends Drawing {

       public static int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
Das ist geklärt. Und welche Klassen können von einer statisch verschachtelten Klasse erben? Fast alle! Verschachtelt/regulär, statisch/nicht statisch – das spielt keine Rolle. Hier erben wir die innere Klasse Boeing737Drawingvon der statisch verschachtelten Drawing:
public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

   }

   public class Boeing737Drawing extends Drawing {

       public int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
Sie können eine Instanz Boeing737Drawingwie folgt erstellen:
public class Main {

   public static void main(String[] args) {

      Boeing737 boeing737 = new Boeing737(1990);
      Boeing737.Boeing737Drawing drawing = boeing737.new Boeing737Drawing();
      System.out.println(drawing.getMaxPassengersCount());

   }

}
Obwohl unsere Klasse Boeing737Drawingvon einer statischen Klasse erbt, ist sie selbst nicht statisch! Daher wird immer eine Instanz der äußeren Klasse benötigt. Wir können die Klasse Boeing737Drawingaus der Klasse herausnehmen Boeing737und sie zu einer öffentlichen Klasse machen. Es ändert sich nichts – es kann auch von einer statischen verschachtelten Datei erben Drawing.
public class Boeing737 {

   private int manufactureYear;
   public static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

   }
}

public class Boeing737Drawing extends Boeing737.Drawing {

   public int getMaxPassengersCount() {

       return Boeing737.maxPassengersCount;

}
Der einzig wichtige Punkt: In diesem Fall müssen wir die statische Variable maxPassengersCountöffentlich machen. Wenn es privat bleibt, hat die normale öffentliche Klasse keinen Zugriff darauf. Wir haben statische Klassen aussortiert! :) Kommen wir nun zu den inneren Klassen. Wie Sie sich erinnern, gibt es drei Arten davon: einfache innere Klassen, lokale Klassen und anonyme innere Klassen. Beispiele für die Vererbung interner Klassen - 3Kommen wir noch einmal vom Einfachen zum Komplexen :)

Anonyme innere Klassen

Eine anonyme innere Klasse kann nicht von einer anderen Klasse erben. Keine andere Klasse kann von einer anonymen Klasse erben. Es könnte nicht einfacher sein! :) :)

Lokale Klassen

Lokale Klassen (falls Sie es vergessen haben) werden innerhalb eines Codeblocks einer anderen Klasse deklariert. Am häufigsten - innerhalb einer Methode dieser äußeren Klasse. Es ist logisch, dass nur andere lokale Klassen innerhalb derselben Methode (oder desselben Blocks) von einer lokalen Klasse erben können. Hier ist ein Beispiel:
public class PhoneNumberValidator {

   public void validatePhoneNumber(final String number) {

       class PhoneNumber {

           private String phoneNumber;

           public PhoneNumber() {
               this.phoneNumber = number;
           }

           public String getPhoneNumber() {
               return phoneNumber;
           }

           public void setPhoneNumber(String phoneNumber) {
               this.phoneNumber = phoneNumber;
           }
       }

       class CellPhoneNumber extends PhoneNumber {

       }

       class LandlinePhoneNumber extends PhoneNumber {


       }

       //...Code валидации номера
   }
}
Dies ist der Code aus unserem Vortrag über lokale Klassen. Innerhalb der Nummernvalidatorklasse haben wir eine lokale Klasse PhoneNumber– Telefonnummer. Wenn wir für unsere Zwecke zwei separate Entitäten daraus extrahieren müssen, beispielsweise eine Mobiltelefonnummer und eine Festnetznummer, können wir dies nur mit derselben Methode tun. Der Grund ist einfach: Der Gültigkeitsbereich einer lokalen Klasse liegt innerhalb der Methode (Block), in der sie deklariert wird. Daher können wir es nicht irgendwie extern verwenden (auch nicht zur Vererbung). Die lokale Klasse selbst verfügt jedoch über größere Vererbungsmöglichkeiten! Eine lokale Klasse kann erben von:
  1. Regelmäßige Klasse.
  2. Eine innere Klasse, die in derselben Klasse wie die lokale Klasse oder in ihren Vorgängern deklariert ist.
  3. Von einer anderen lokalen Klasse, die in derselben Methode (Block) deklariert wurde.
Der erste und dritte Punkt sehen offensichtlich aus, aber der zweite ist etwas verwirrend :/ Schauen wir uns zwei Beispiele an. Beispiel 1 – „Erben einer lokalen Klasse von einer inneren Klasse, die in derselben Klasse wie die lokale Klasse deklariert wurde“:
public class PhoneNumberValidator {

   class PhoneNumber {

       private String phoneNumber;

       public PhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }

       public String getPhoneNumber() {
           return phoneNumber;
       }

       public void setPhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }
   }

   public void validatePhoneNumber(final String number) {

       class CellPhoneNumber extends PhoneNumber {

           public CellPhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       class LandlinePhoneNumber extends PhoneNumber {

           public LandlinePhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       //...Code валидации номера
   }
}
Hier haben wir die Klasse PhoneNumberaus der Methode herausgenommen validatePhoneNumber()und sie intern statt lokal gemacht. Dies hindert uns nicht daran, unsere beiden lokalen Klassen davon zu erben. Beispiel 2 – „...oder in den Vorfahren dieser Klasse.“ Hier wird es interessanter. Wir können es PhoneNumberin der Vererbungskette noch weiter nach oben bringen. Lassen Sie uns eine abstrakte Klasse deklarieren, AbstractPhoneNumberValidatordie unser Vorfahre wird PhoneNumberValidator:
public abstract class AbstractPhoneNumberValidator {

   class PhoneNumber {

       private String phoneNumber;

       public PhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }

       public String getPhoneNumber() {
           return phoneNumber;
       }

       public void setPhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }
   }

}
Wie Sie sehen, haben wir es nicht nur deklariert, sondern auch die innere Klasse hinein verschoben PhoneNumber. Allerdings können lokale Klassen in Methoden in ihrer Nachkommenklasse PhoneNumberValidatorerben von PhoneNumber!
public class PhoneNumberValidator extends AbstractPhoneNumberValidator {

   public void validatePhoneNumber(final String number) {

       class CellPhoneNumber extends PhoneNumber {

           public CellPhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       class LandlinePhoneNumber extends PhoneNumber {

           public LandlinePhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       //...Code валидации номера
   }
}
Dank der Verbindung durch Vererbung „sehen“ lokale Klassen innerhalb einer Nachkommenklasse innere Klassen innerhalb der Vorfahrenklasse. Und zum Schluss kommen wir zur letzten Gruppe :)

Innere Klassen

Eine innere Klasse kann von einer anderen inneren Klasse geerbt werden, die in derselben äußeren Klasse (oder ihrem Nachkommen) deklariert ist. Schauen wir uns das anhand unseres Fahrradbeispiels aus der Vorlesung „Innere Klassen“ an.
public class Bicycle {

   private String model;
   private int mawWeight;

   public Bicycle(String model, int mawWeight) {
       this.model = model;
       this.mawWeight = mawWeight;
   }

   public void start() {
       System.out.println("Gehen!");
   }

   class Seat {

       public void up() {

           System.out.println("Сидение поднято выше!");
       }

       public void down() {

           System.out.println("Сидение опущено ниже!");
       }
   }

   class SportSeat extends Seat {

       //...Methoden
   }
}
BicycleHier haben wir eine interne Klasse innerhalb der Klasse deklariert Seat– Platz. Von ihm wurde eine spezielle Unterart der Rennsitze übernommen – SportSeat. Wir könnten jedoch einen separaten Typ „Rennräder“ erstellen und ihn einer separaten Klasse zuordnen:
public class SportBicycle extends Bicycle {

   public SportBicycle(String model, int mawWeight) {
       super(model, mawWeight);
   }


   class SportSeat extends Seat {

       public void up() {

           System.out.println("Сидение поднято выше!");
       }

       public void down() {

           System.out.println("Сидение опущено ниже!");
       }
   }
}
Auch das ist möglich. Die innere Klasse des Kindes ( SportBicycle.SportSeat) „sieht“ die inneren Klassen des Vorfahren und kann von ihnen erben. Die Vererbung von inneren Klassen hat ein sehr wichtiges Merkmal! In den beiden vorherigen Beispielen SportSeathatten wir internal. Was aber, wenn wir uns dafür entscheiden, daraus SportSeateine reguläre öffentliche Klasse zu machen, die auch von der inneren Klasse erbt Seat?
//ошибка! No inclosing instance of  type 'Bicycle' is in scope
class SportSeat extends Bicycle.Seat {

   public SportSeat() {

   }

   public void up() {

       System.out.println("Сидение поднято выше!");
   }

   public void down() {

       System.out.println("Сидение опущено ниже!");
   }
}
Es ist ein Fehler aufgetreten! Können Sie erraten, womit es zusammenhängt? :) Es ist einfach. Als wir über die innere Klasse sprachen Bicycle.Seat, erwähnten wir, dass der Konstruktor der inneren Klasse implizit einen Verweis auf ein Objekt der äußeren Klasse übergibt. Daher Bicyclekönnen Sie kein Objekt erstellen, ohne ein Objekt zu erstellen Seat. Was ist mit der Schöpfung SportSeat? Es verfügt nicht über denselben integrierten Mechanismus zur impliziten Übergabe eines Verweises auf ein äußeres Klassenobjekt im Konstruktor wie in Seat. Ohne ein Objekt können wir jedoch Bicycle, genau wie im Fall von Seat, kein Objekt erstellen SportSeat. Daher bleibt uns nur noch eines zu tun – dem Konstruktor explizit SportSeateine Referenz auf das Objekt zu übergeben. BicycleSo wird es gemacht:
class SportSeat extends Bicycle.Seat {

   public SportSeat(Bicycle bicycle) {

       bicycle.super();
   }

   public void up() {

       System.out.println("Сидение поднято выше!");
   }

   public void down() {

       System.out.println("Сидение опущено ниже!");
   }
}
Dafür verwenden wir ein spezielles Wort super(); . Wenn wir nun ein Objekt erstellen möchten SportSeat, hindert uns nichts daran, dies zu tun:
public class Main {

   public static void main(String[] args) {

       Bicycle bicycle = new Bicycle("Peugeot", 120);
       SportSeat peugeotSportSeat = new SportSeat(bicycle);

   }
}
Puh, der Vortrag ist ganz schön groß geworden :) Aber man hat viel Neues gelernt! Jetzt ist es an der Zeit, ein paar Probleme zu lösen! :) :)
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION