CodeGym /Java blog /Véletlen /Példák a beágyazott osztályok öröklésére
John Squirrels
Szint
San Francisco

Példák a beágyazott osztályok öröklésére

Megjelent a csoportban
Szia! Ma egy fontos mechanizmust fogunk megvizsgálni: az öröklődést a beágyazott osztályokban. Gondolt már arra, hogy mit tenne, ha egy beágyazott osztályt szeretne örökölni egy másik osztályt. Ha nem, hidd el: ez a helyzet zavaró lehet, mert nagyon sok árnyalat van.
  1. Egy beágyazott osztályt örökölünk valamilyen osztályra? Vagy valamilyen osztályt örökölünk egy beágyazott osztályba?
  2. A gyermek/szülő osztály közönséges nyilvános osztály, vagy egyben beágyazott osztály?
  3. Végül, milyen típusú beágyazott osztályokat használunk ezekben a helyzetekben?
Annyi lehetséges válasz van ezekre a kérdésekre, meg fog fordulni a fejed :) Mint tudod, egyszerűbb részekre bontva egy összetett problémát megoldhatunk. Csináljuk meg. Vizsgáljuk meg az egyes beágyazott osztályok csoportjait két szempontból: ki örökölheti az egyes beágyazott osztályokat, és kik örökölhetik. Kezdjük a statikus beágyazott osztályokkal.

Statikus beágyazott osztályok

Példák a beágyazott osztályok öröklődésére - 2Öröklési szabályaik a legegyszerűbbek. Itt szinte bármit megtehetsz, amire a szíved vágyik. Egy statikus beágyazott osztály örökölheti:
  • hétköznapi osztály
  • statikus beágyazott osztály, amely egy külső osztályban vagy annak őseiben van deklarálva
Idézzünk fel egy példát a statikus beágyazott osztályokról szóló leckénkből.

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;
       }
   }
}
Próbáljuk meg megváltoztatni a kódot, és létrehozni egy Drawingstatikus beágyazott osztályt és leszármazottját — 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;
       }
   }
}
Amint látja, nincs probléma. Akár ki is húzhatjuk az Drawingosztályt, és közönséges nyilvános osztállyá tehetjük statikus beágyazott osztály helyett – semmi sem fog változni.

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;
       }
   }
}
Ezt megértjük. De milyen osztályok örökölhetnek egy statikus beágyazott osztályt? Gyakorlatilag bármelyik! Beágyazott/nem beágyazott, statikus/nem statikus – mindegy. Itt a Boeing737Drawingbelső osztály örökli a Drawingstatikus beágyazott osztályt:

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;
       }
   }
}
Létrehozhat egy Boeing737Drawingilyen példányt:

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());

   }

}
Bár a mi Boeing737Drawingosztályunk örököl egy statikus osztályt, maga nem statikus! Ennek eredményeként mindig szüksége lesz a külső osztály egy példányára. Eltávolíthatjuk az Boeing737Drawingosztályt az Boeing737osztályból, és egyszerű nyilvános osztályt készíthetünk belőle. Semmi sem változik. Továbbra is örökölheti a Drawingstatikus beágyazott osztályt.

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;
   
}
Az egyetlen fontos pont az, hogy ebben az esetben nyilvánossá kell tennünk a statikus maxPassengersCountváltozót. Ha privát marad, akkor egy közönséges nyilvános osztály nem fér hozzá. Kitaláltuk a statikus osztályokat! :) Most pedig térjünk át a belső órákra. Három típusuk van: egyszerű belső osztályok, helyi osztályok és névtelen belső osztályok. Példák a beágyazott osztályok öröklésére - 3Ismét térjünk át az egyszerűről a bonyolultra :)

Névtelen belső osztályok

Egy névtelen belső osztály nem örökölhet másik osztályt. Más osztály nem örökölhet névtelen osztályt. Ennél egyszerűbb nem is lehetne! :)

Helyi osztályok

A helyi osztályok (ha elfelejtették) egy másik osztály kódblokkjában vannak deklarálva. Leggyakrabban ez a külső osztály valamelyik metódusán belül történik. Logikailag csak az ugyanazon a metóduson (vagy kódblokkon) belüli más helyi osztályok örökölhetnek egy helyi osztályt. Íme egy példa:

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
   }
}
Ez a kód a helyi osztályokról szóló leckénkből. Számellenőrző osztályunknak van egy PhoneNumberhelyi osztálya. Ha arra van szükségünk, hogy két különálló entitást képviseljen, például egy mobiltelefon-számot és egy vezetékes telefonszámot, akkor ezt csak ugyanazon a módszeren belül tehetjük meg. Az ok egyszerű: egy helyi osztály hatóköre arra a metódusra (kódblokkra) korlátozódik, ahol deklarálva van. Ennek eredményeként nem fogjuk tudni használni külsőleg (beleértve az osztályöröklést sem). Magán a helyi osztályon belül azonban az öröklés lehetőségei sokkal szélesebbek! Egy helyi osztály örökölheti:
  1. Közönséges osztály.
  2. Egy belső osztály, amely ugyanabban az osztályban van deklarálva, mint a helyi osztály, vagy annak egyik őse.
  3. Egy másik helyi osztály deklarált ugyanabban a metódusban (kódblokk).
Az első és a harmadik pont kézenfekvőnek tűnik, de a második kicsit zavaró :/ Nézzünk két példát. 1. példa – "Egy helyi osztály örökölése egy belső osztályt, amely ugyanabban az osztályban van deklarálva, mint a helyi osztály":

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
   }
}
Itt eltávolítottuk az PhoneNumberosztályt a validatePhoneNumber()metódusból, és helyi osztály helyett belső osztály lett. Ez nem akadályoz meg minket abban, hogy 2 helyi osztályunk örökölje. 2. példa — "... vagy ennek az osztálynak az őseinél." Most ez már érdekesebb. PhoneNumberAz öröklési láncban még feljebb léphetünk . Deklaráljunk egy absztrakt AbstractPhoneNumberValidatorosztályt, amely osztályunk őse lesz 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;
       }
   }

}
Mint látható, nem csak deklaráltuk, hanem a PhoneNumberbelső osztályt is áthelyeztük ebbe. A leszármazottjában azonban a metódusokban deklarált lokális osztályok probléma nélkül PhoneNumberValidatorörökölhetnek !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);
           }
       }

       // ...number validation code
   }
}
Az öröklődési kapcsolat miatt a leszármazott osztályon belüli helyi osztályok egy ősön belül "látják" a belső osztályokat. És végül folytassuk az utolsó csoporttal :)

Belső osztályok

Az ugyanabban a külső osztályban (vagy leszármazottjában) deklarált belső osztály örökölhet egy másik belső osztályt. Vizsgáljuk meg ezt a kerékpárokkal kapcsolatos példánkkal a belső osztályokról szóló leckében.

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
   }
}
Itt deklaráltuk a Seatbelső osztályt az Bicycleosztályon belül. Egy különleges típusú versenyülés SportSeatörökli. De létrehozhatunk egy külön "versenykerékpár" típust, és egy külön osztályba helyezhetjük:

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!");
       }
   }
}
Ez is egy lehetőség. A leszármazott ( SportBicycle.SportSeat) belső osztálya "látja" az ős belső osztályait, és örökölheti azokat. A belső osztályok öröklésének van egy nagyon fontos tulajdonsága! Az előző két példában a mi SportSeatosztályunk belső osztály volt. De mi van, ha úgy döntünk, hogy SportSeategy közönséges nyilvános osztályt hozunk létre, amely egyidejűleg örökli a Seatbelső osztályt?

// 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!");
   }
}
Hibát kaptunk! Kitalálod miért? :) Minden egyértelmű. Amikor a belső osztályról beszéltünk Bicycle.Seat, megemlítettük, hogy a külső osztály egy példányára való hivatkozás implicit módon átadódik a belső osztály konstruktorának. Ez azt jelenti, hogy nem hozhat létre Seatobjektumot objektum létrehozása nélkül Bicycle. De mi a helyzet a létrehozásával SportSeat? Ellentétben a -val Seat, nem rendelkezik ezzel a beépített mechanizmussal, amely implicit módon átadja a konstruktornak a külső osztály egy példányára való hivatkozást. S amíg Bicycleobjektum nélkül nem tudunk SportSeatobjektumot létrehozni, akárcsak az esetében Seat. Ezért csak egy dolgot kell tennünk – kifejezetten át kell adni a SportSeatkonstruktornak egy objektumra való hivatkozást Bicycle. Íme, hogyan kell csinálni:

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!");
   }
}
A szuperosztály-konstruktort a Now segítségével hívjuk super(); , ha objektumot akarunk létrehozni SportSeat, semmi sem akadályoz meg ebben:

public class Main {

   public static void main(String[] args) {

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

   }
}
Fú! Ez a lecke elég hosszú volt :) De sokat tanultál! Itt az ideje néhány feladat megoldásának! :)
Hozzászólások
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION