JavaRush /Java Blog /Random-TL /Pamana ng mga nested na klase

Pamana ng mga nested na klase

Nai-publish sa grupo
Kamusta! Ngayon ay titingnan natin ang pagpapatakbo ng isang mahalagang mekanismo - mana sa mga nested na klase. Hindi ko alam kung naisip mo na kung ano ang gagawin mo kapag kailangan mong magmana ng nested class mula sa iba. Kung hindi, maniwala ka sa akin: ang sitwasyong ito ay maaaring nakalilito, dahil mayroong maraming mga nuances dito:
  1. Nagmana ba tayo ng nested class mula sa ilang klase o nagmana ba tayo ng isa pang klase mula sa nested na klase?
  2. Ang kahalili/nagmana ba ay isang regular na pampublikong klase, o ito ba ay isang nested na klase?
  3. Sa wakas, anong eksaktong uri ng mga nested na klase ang ginagamit namin sa lahat ng mga sitwasyong ito?
Kung sasagutin mo ang lahat ng mga tanong na ito, magkakaroon ng napakaraming posibleng sagot na iikot ang iyong ulo :) Tulad ng alam mo, upang malutas ang isang kumplikadong problema, kailangan mong hatiin ito sa mas simpleng mga bahagi. Yan ang gagawin natin. Tingnan natin ang bawat pangkat ng mga nested na klase sa turn mula sa dalawang pananaw: sino ang maaaring magmana mula sa ganitong uri ng nested class, at kung kanino ito maaaring magmana. Magsimula tayo sa mga static na nested na klase.

Mga static na nested na klase

Mga halimbawa ng pamana ng mga panloob na klase - 2Ang kanilang mga alituntunin ng pamana ay ang pinakasimple. Dito maaari mong gawin ang halos anumang naisin ng iyong puso. Ang isang static na nested na klase ay maaaring mamana mula sa:
  • regular na klase
  • isang static na nested class na idineklara sa outer class o sa mga ninuno nito
Tandaan natin ang halimbawa mula sa lecture tungkol sa mga static na nested na klase.
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;
       }
   }
}
Subukan nating baguhin ang code at lumikha ng isang static na nested class Drawingat ang descendant nito - 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;
       }
   }
}
Tulad ng nakikita mo, walang problema. Maaari nating alisin ang klase nang buo Drawingat gawin itong isang regular na pampublikong klase sa halip na isang static na nested - walang magbabago.
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;
       }
   }
}
Naayos na yan. At anong mga klase ang maaaring magmana mula sa isang static na nested? Halos kahit ano! Nested/regular, static/non-static - hindi mahalaga. Dito namin namana ang panloob na klase Boeing737Drawingmula sa static na nested one 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;
       }
   }
}
Maaari kang lumikha ng isang instance Boeing737Drawingtulad nito:
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());

   }

}
Bagama't ang aming klase Boeing737Drawingay nagmana mula sa isang static na klase, ito mismo ay hindi static! Samakatuwid ito ay palaging nangangailangan ng isang halimbawa ng panlabas na klase. Maaari nating alisin ang klase Boeing737Drawingsa klase Boeing737at gawin itong pampublikong klase lamang. Walang magbabago - maaari din itong magmana mula sa isang static na nested 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;

}
Ang tanging mahalagang punto: sa kasong ito kailangan nating gawing maxPassengersCountpampubliko ang static na variable. Kung ito ay mananatiling pribado, ang normal na pampublikong klase ay hindi magkakaroon ng access dito. Inayos namin ang mga static na klase! :) Ngayon ay lumipat tayo sa mga panloob na klase. Tulad ng naaalala mo, mayroong 3 uri ng mga ito: simpleng mga panloob na klase, mga lokal na klase at hindi kilalang mga panloob na klase. Mga halimbawa ng pamana ng mga panloob na klase - 3Muli, lumipat tayo mula sa simple patungo sa kumplikado :)

Anonymous na mga panloob na klase

Ang isang hindi kilalang panloob na klase ay hindi maaaring magmana mula sa ibang klase. Walang ibang klase ang maaaring magmana mula sa isang hindi kilalang klase. Hindi ito maaaring maging mas simple! :)

Mga lokal na klase

Ang mga lokal na klase (kung sakaling nakalimutan mo) ay idineklara sa loob ng isang bloke ng code ng isa pang klase. Kadalasan - sa loob ng ilang pamamaraan ng panlabas na klase na ito. Ito ay lohikal na tanging ang iba pang mga lokal na klase sa loob ng parehong pamamaraan (o block) ang maaaring magmana mula sa isang lokal na klase. Narito ang isang halimbawa:
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 валидации номера
   }
}
Ito ang code mula sa aming panayam tungkol sa mga lokal na klase. Sa loob ng klase ng validator ng numero mayroon kaming lokal na klase PhoneNumber- numero ng telepono. Kung para sa aming mga layunin kailangan naming paghiwalayin ang dalawang magkahiwalay na entity mula dito, halimbawa, isang numero ng mobile phone at isang landline na numero ng telepono, magagawa lang namin ito sa loob ng parehong paraan. Ang dahilan ay simple: ang saklaw ng isang lokal na klase ay nasa loob ng pamamaraan (block) kung saan ito idineklara. Samakatuwid, hindi namin ito magagamit sa anumang paraan sa labas (kabilang ang para sa mana). Gayunpaman, ang lokal na klase mismo ay may mas malawak na posibilidad para sa mana! Ang isang lokal na klase ay maaaring magmana mula sa:
  1. Regular na klase.
  2. Isang panloob na uri na idineklara sa parehong klase ng lokal na uri o sa mga ninuno nito.
  3. Mula sa isa pang lokal na klase na ipinahayag sa parehong pamamaraan (block).
Ang una at pangatlong puntos ay mukhang halata, ngunit ang pangalawa ay medyo nakakalito :/ Tingnan natin ang dalawang halimbawa. Halimbawa 1 - "pagmana ng isang lokal na klase mula sa isang panloob na klase na idineklara sa parehong klase ng lokal na klase":
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 валидации номера
   }
}
Dito ay inalis namin ang klase PhoneNumbersa pamamaraan validatePhoneNumber()at ginawa itong panloob sa halip na lokal. Hindi ito pumipigil sa amin na magmana ng aming 2 lokal na klase mula rito. Halimbawa 2 – “...o sa mga ninuno ng klaseng ito.” Ito ay kung saan ito ay nagiging mas kawili-wili. Maaari nating dalhin ito PhoneNumbernang mas mataas pa sa kadena ng mana. Magdeklara tayo ng abstract class AbstractPhoneNumberValidatorna magiging ninuno natin 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;
       }
   }

}
Tulad ng nakikita mo, hindi lamang namin ito idineklara, ngunit inilipat din ang panloob na uri dito PhoneNumber. Gayunpaman, sa descendant class nito - PhoneNumberValidator- ang mga lokal na klase sa mga pamamaraan ay maaaring magmana mula sa 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 валидации номера
   }
}
Salamat sa koneksyon sa pamamagitan ng mana, ang mga lokal na klase sa loob ng isang descendant na klase ay "nakikita" ang mga panloob na klase sa loob ng ninuno. At sa wakas, lumipat tayo sa huling grupo :)

Mga panloob na klase

Ang isang panloob na klase ay maaaring mamana ng isa pang panloob na klase na idineklara sa parehong panlabas na klase (o ang inapo nito). Tingnan natin ito gamit ang aming halimbawa ng bisikleta mula sa lecture sa mga panloob na klase.
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("Go!");
   }

   class Seat {

       public void up() {

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

       public void down() {

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

   class SportSeat extends Seat {

       //...methods
   }
}
BicycleDito kami nagdeklara ng panloob na klase sa loob ng klase Seat- upuan. Ang isang espesyal na subtype ng mga upuan sa karera ay minana mula dito - SportSeat. Gayunpaman, maaari kaming lumikha ng isang hiwalay na uri ng "mga racing bike" at ilagay ito sa isang hiwalay na klase:
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("Сидение опущено ниже!");
       }
   }
}
Posible rin ito. Ang panloob na uri ng bata ( SportBicycle.SportSeat) ay “nakikita” ang mga panloob na uri ng ninuno at maaaring magmana mula sa kanila. Ang mana mula sa mga panloob na klase ay may isang napakahalagang katangian! Sa nakaraang dalawang halimbawa SportSeatmayroon kaming panloob. Ngunit paano kung magpasya tayong gawin itong SportSeatisang regular na pampublikong klase, na nagmamana rin mula sa panloob na uri 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("Сидение опущено ниже!");
   }
}
Nagkaroon kami ng error! Maaari mo bang hulaan kung ano ang konektado nito? :) Simple lang. Noong pinag-usapan natin ang inner class Bicycle.Seat, binanggit namin na ang constructor ng inner class ay tahasang nagpapasa ng reference sa isang object ng outer class. Samakatuwid, nang hindi lumilikha ng isang bagay, Bicyclehindi ka makakalikha ng isang bagay Seat. Paano ang tungkol sa paglikha SportSeat? Wala itong parehong built-in na mekanismo para sa tahasang pagpasa ng isang sanggunian sa isang panlabas na uri ng bagay sa konstruktor tulad ng sa Seat. Gayunpaman, kung walang object Bicycle, tulad ng sa kaso ng Seat, hindi kami makakalikha ng object SportSeat. Samakatuwid, mayroon na lamang kaming isang bagay na natitira upang gawin - tahasang ipasa SportSeatang isang reference sa bagay sa constructor. BicycleNarito kung paano ito ginagawa:
class SportSeat extends Bicycle.Seat {

   public SportSeat(Bicycle bicycle) {

       bicycle.super();
   }

   public void up() {

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

   public void down() {

       System.out.println("Сидение опущено ниже!");
   }
}
Para dito gumagamit kami ng isang espesyal na salita super(); Ngayon, kung gusto naming lumikha ng isang bagay SportSeat, walang makakapigil sa aming gawin ito:
public class Main {

   public static void main(String[] args) {

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

   }
}
Phew, medyo malaki pala ang lecture :) Pero marami kang natutunang bagong bagay! Ngayon ang oras upang malutas ang ilang mga problema! :)
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION