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.
Ö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:
Ismét térjünk át az egyszerűről a bonyolultra :)
- 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?
- A gyermek/szülő osztály közönséges nyilvános osztály, vagy egyben beágyazott osztály?
- Végül, milyen típusú beágyazott osztályokat használunk ezekben a helyzetekben?
Statikus beágyazott osztályok

- hétköznapi osztály
- statikus beágyazott osztály, amely egy külső osztályban vagy annak őseiben van deklarálva
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 Drawing
statikus 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 Drawing
osztá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 Boeing737Drawing
belső osztály örökli a Drawing
statikus 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 Boeing737Drawing
ilyen 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 Boeing737Drawing
osztá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 Boeing737Drawing
osztályt az Boeing737
osztá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 Drawing
statikus 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 maxPassengersCount
vá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. 
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 PhoneNumber
helyi 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:
- Közönséges osztály.
- Egy belső osztály, amely ugyanabban az osztályban van deklarálva, mint a helyi osztály, vagy annak egyik őse.
- Egy másik helyi osztály deklarált ugyanabban a metódusban (kódblokk).
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 PhoneNumber
osztá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. PhoneNumber
Az öröklési láncban még feljebb léphetünk . Deklaráljunk egy absztrakt AbstractPhoneNumberValidator
osztá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 PhoneNumber
belső 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 Seat
belső osztályt az Bicycle
osztá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 SportSeat
osztályunk belső osztály volt. De mi van, ha úgy döntünk, hogy SportSeat
egy közönséges nyilvános osztályt hozunk létre, amely egyidejűleg örökli a Seat
belső 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 Seat
objektumot 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 Bicycle
objektum nélkül nem tudunk SportSeat
objektumot létrehozni, akárcsak az esetében Seat
. Ezért csak egy dolgot kell tennünk – kifejezetten át kell adni a SportSeat
konstruktornak 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! :)
GO TO FULL VERSION