CodeGym/Java blog/Tilfældig/Eksempler på nedarvning af indlejrede klasser
John Squirrels
Niveau
San Francisco

Eksempler på nedarvning af indlejrede klasser

Udgivet i gruppen
Hej! I dag skal vi se på en vigtig mekanisme: arv i indlejrede klasser. Har du nogensinde tænkt over, hvad du ville gøre, hvis du skulle få en indlejret klasse til at arve en anden klasse. Hvis ikke, tro mig: denne situation kan være forvirrende, fordi der er mange nuancer.
  1. Får vi en indlejret klasse til at arve en eller anden klasse? Eller får vi en klasse til at arve en indlejret klasse?
  2. Er børne-/forældreklassen en almindelig offentlig klasse, eller er det også en indlejret klasse?
  3. Til sidst, hvilken type indlejrede klasser bruger vi i alle disse situationer?
Der er så mange mulige svar på alle disse spørgsmål, dit hoved vil snurre :) Som du ved, kan vi løse et komplekst problem ved at dele det op i mere simple dele. Lad os gøre det. Lad os overveje hver gruppe af indlejrede klasser på skift fra to perspektiver: hvem kan arve hver type indlejret klasse, og hvem den kan arve. Lad os starte med statiske indlejrede klasser.

Statiske indlejrede klasser

Eksempler på nedarvning af indlejrede klasser - 2Deres arveregler er de enkleste. Her kan du lave næsten alt hvad hjertet begærer. En statisk indlejret klasse kan arve:
  • en almindelig klasse
  • en statisk indlejret klasse, der er erklæret i en ydre klasse eller dens forfædre
Husk et eksempel fra vores lektion om statiske indlejrede klasser.
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;
       }
   }
}
Lad os prøve at ændre koden og oprette en Drawingstatisk indlejret klasse og dens efterkommer — 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;
       }
   }
}
Som du kan se, intet problem. Vi kan endda trække klassen ud Drawingog gøre den til en almindelig offentlig klasse i stedet for en statisk indlejret klasse - intet vil ændre sig.
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;
       }
   }
}
Vi forstår dette. Men hvilke klasser kan arve en statisk indlejret klasse? Næsten alle! Indlejret/ikke-indlejret, statisk/ikke-statisk — det er lige meget. Her får vi den Boeing737Drawingindre klasse til at arve den Drawingstatiske indlejrede klasse:
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;
       }
   }
}
Du kan oprette en instans af Boeing737Drawingsådan her:
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());

   }

}
Selvom vores Boeing737Drawingklasse arver en statisk klasse, er den ikke statisk i sig selv! Som et resultat vil den altid have brug for en forekomst af den ydre klasse. Vi kan fjerne Boeing737Drawingklassen fra Boeing737klassen og gøre den til en simpel offentlig klasse. Intet ændrer sig. Den kan stadig arve den Drawingstatiske indlejrede klasse.
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;

}
Det eneste vigtige punkt er, at vi i dette tilfælde skal gøre den statiske maxPassengersCountvariabel offentlig. Hvis det forbliver privat, så vil en almindelig offentlig klasse ikke have adgang til det. Vi har fundet ud af statiske klasser! :) Lad os nu gå videre til indre klasser. De findes i 3 typer: simple indre klasser, lokale klasser og anonyme indre klasser. Eksempler på nedarvning af indlejrede klasser - 3Igen, lad os gå fra simpelt til komplekst :)

Anonyme indre klasser

En anonym indre klasse kan ikke arve en anden klasse. Ingen anden klasse kan arve en anonym klasse. Det kunne ikke være nemmere! :)

Lokale klasser

Lokale klasser (i tilfælde af at du har glemt det) erklæres inde i en kodeblok af en anden klasse. Oftest sker dette inde i en eller anden metode i den ydre klasse. Logisk set kan kun andre lokale klasser inden for samme metode (eller kodeblok) arve en lokal klasse. Her er et eksempel:
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 {


       }

       // ...number validation code
   }
}
Dette er koden fra vores lektion om lokale klasser. Vores nummervalideringsklasse har en PhoneNumberlokal klasse. Hvis vi har brug for det til at repræsentere to adskilte enheder, for eksempel et mobiltelefonnummer og et fastnettelefonnummer, kan vi kun gøre dette inden for den samme metode. Årsagen er enkel: En lokal klasses omfang er begrænset til den metode (kodeblok), hvor den er deklareret. Som følge heraf vil vi ikke være i stand til at bruge det eksternt (inklusive til klassearv). Mulighederne for arv inden for selve lokalklassen er dog meget bredere! En lokal klasse kan arve:
  1. En almindelig klasse.
  2. En indre klasse, der er erklæret i samme klasse som den lokale klasse eller i en af ​​dens forfædre.
  3. En anden lokal klasse erklæret i samme metode (kodeblok).
Det første og tredje punkt ser indlysende ud, men det andet er lidt forvirrende :/ Lad os se på to eksempler. Eksempel 1 - "At få en lokal klasse til at arve en indre klasse erklæret i samme klasse som den lokale klasse":
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);
           }
       }

       // ...number validation code
   }
}
Her fjernede vi PhoneNumberklassen fra validatePhoneNumber()metoden og gjorde den til en indre klasse i stedet for en lokal klasse. Dette forhindrer os ikke i at få vores 2 lokale klasser til at arve det. Eksempel 2 - "... eller i denne klasses forfædre." Nu er dette allerede mere interessant. Vi kan rykke PhoneNumberendnu højere op i arvekæden. Lad os erklære en abstrakt AbstractPhoneNumberValidatorklasse, som vil blive forfaderen til vores PhoneNumberValidatorklasse:
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;
       }
   }

}
Som du kan se, erklærede vi det ikke bare – vi flyttede også den PhoneNumberindre klasse ind i det. Men i dens efterkommer PhoneNumberValidatorkan lokale klasser, der er erklæret i metoder, arve PhoneNumberuden problemer!
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);
           }
       }

       // ...number validation code
   }
}
På grund af arveforholdet "ser" de lokale klasser inde i en efterkommerklasse de indre klasser inde i en forfader. Og endelig, lad os gå videre til den sidste gruppe :)

Indre klasser

En indre klasse erklæret i den samme ydre klasse (eller i dens efterkommer) kan arve en anden indre klasse. Lad os undersøge dette ved at bruge vores eksempel med cykler fra lektionen om indre klasser.
public class Bicycle {

   private String model;
   private int maxWeight;

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

   public void start() {
       System.out.println("Let's go!");
   }

   class Seat {

       public void up() {

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

       public void down() {

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

   class SportSeat extends Seat {

       // ...methods
   }
}
Her erklærede vi den Seatindre klasse inde i Bicycleklassen. En speciel type racersæde, SportSeat, arver det. Men vi kunne oprette en separat "racercykel" type og placere den i en separat klasse:
public class SportBicycle extends Bicycle {

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


   class SportSeat extends Seat {

       public void up() {

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

       public void down() {

           System.out.println("Seat down!");
       }
   }
}
Dette er også en mulighed. Den indre klasse af efterkommeren ( SportBicycle.SportSeat) "ser" forfaderens indre klasser og kan arve dem. At arve indre klasser har en meget vigtig egenskab! I de to foregående eksempler SportSeatvar vores klasse en indre klasse. Men hvad nu hvis vi beslutter os for at lave SportSeaten almindelig offentlig klasse, der samtidig arver den Seatindre klasse?
// Error! No enclosing instance of type 'Bicycle' is in scope
class SportSeat extends Bicycle.Seat {

   public SportSeat() {

   }

   public void up() {

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

   public void down() {

       System.out.println("Seat down!");
   }
}
Vi har en fejl! Kan du gætte hvorfor? :) Det hele er ligetil. Da vi talte om den Bicycle.Seatindre klasse, nævnte vi, at en reference til en instans af den ydre klasse implicit videregives til konstruktøren af ​​den indre klasse. Det betyder, at du ikke kan oprette et Seatobjekt uden at oprette et Bicycleobjekt. Men hvad med oprettelsen af ​​en SportSeat? I modsætning til Seat, har den ikke denne indbyggede mekanisme til implicit at sende konstruktøren en reference til en instans af den ydre klasse. S till, uden et Bicycleobjekt, kan vi ikke skabe et SportSeatobjekt, ligesom i tilfældet med Seat. Derfor er der kun én ting tilbage for os at gøre - eksplicit videregive SportSeaten reference til et Bicycleobjekt til konstruktøren. Sådan gør du:
class SportSeat extends Bicycle.Seat {

   public SportSeat(Bicycle bicycle) {

       bicycle.super();
   }

   public void up() {

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

   public void down() {

       System.out.println("Seat down!");
   }
}
Vi kalder superklassens konstruktør ved hjælp af super(); Nu, hvis vi vil oprette et SportSeatobjekt, vil intet forhindre os i at gøre dette:
public class Main {

   public static void main(String[] args) {

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

   }
}
Pyha! Denne lektion var ret lang :) Men du lærte meget! Nu er det tid til at løse nogle opgaver! :)
Kommentarer
  • Populær
  • Ny
  • Gammel
Du skal være logget ind for at skrive en kommentar
Denne side har ingen kommentarer endnu