JavaRush /وبلاگ جاوا /Random-FA /ارث بری کلاس های تو در تو

ارث بری کلاس های تو در تو

در گروه منتشر شد
سلام! امروز ما به عملکرد یک مکانیسم مهم - وراثت در کلاس های تو در تو نگاه خواهیم کرد. نمی‌دانم تا به حال به این فکر کرده‌اید که وقتی نیاز به ارث بردن یک کلاس تودرتو از یک کلاس دیگر داشته باشید، چه کاری انجام خواهید داد. اگر نه، باور کنید: این وضعیت می تواند گیج کننده باشد، زیرا تفاوت های ظریف زیادی در اینجا وجود دارد:
  1. آیا ما یک کلاس تودرتو از یک کلاس به ارث می بریم یا کلاس دیگری را از یک کلاس تودرتو به ارث می بریم؟
  2. آیا جانشین/ارث شده یک کلاس عمومی معمولی است یا یک کلاس تودرتو نیز هست؟
  3. در نهایت، دقیقاً از چه نوع کلاس های تودرتو در همه این موقعیت ها استفاده می کنیم؟
اگر به همه این سوالات پاسخ دهید، آنقدر پاسخ های احتمالی وجود خواهد داشت که سرتان می چرخد ​​:) همانطور که می دانید، برای حل یک مشکل پیچیده، باید آن را به قسمت های ساده تری تقسیم کنید. این کاری است که ما انجام خواهیم داد. بیایید هر گروه از کلاس‌های تودرتو را به نوبه خود از دو منظر بررسی کنیم: چه کسی می‌تواند از این نوع کلاس تودرتو ارث ببرد و از چه کسی می‌تواند ارث ببرد. بیایید با کلاس های تودرتو ایستا شروع کنیم.

کلاس های تو در تو استاتیک

نمونه هایی از وراثت طبقات داخلی - 2قوانین وراثت آنها ساده ترین است. در اینجا تقریباً می توانید هر کاری که دلتان بخواهد انجام دهید. یک کلاس تودرتو ایستا را می توان از موارد زیر به ارث برد:
  • کلاس معمولی
  • یک کلاس تودرتو ایستا که در کلاس بیرونی یا اجداد آن اعلام شده است
بیایید مثالی از سخنرانی در مورد کلاس های تو در تو ثابت را به خاطر بیاوریم.
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;
       }
   }
}
بیایید سعی کنیم کد را تغییر دهیم و یک کلاس تودرتو ایستا Drawingو نسل آن ایجاد کنیم - 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;
       }
   }
}
همانطور که می بینید مشکلی نیست. ما می‌توانیم کلاس را به‌کلی حذف کنیم Drawingو آن را به‌جای یک کلاس تودرتو ایستا، به یک کلاس عمومی معمولی تبدیل کنیم - هیچ چیز تغییر نخواهد کرد.
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;
       }
   }
}
که مرتب شده است. و چه کلاس هایی را می توان از یک تودرتو ایستا به ارث برد؟ تقریبا هر! تودرتو / منظم، ایستا / غیر ایستا - مهم نیست. در اینجا ما کلاس داخلی را Boeing737Drawingاز کلاس تودرتو استاتیک به ارث می بریم 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;
       }
   }
}
شما می توانید یک نمونه Boeing737Drawingمانند این ایجاد کنید:
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());

   }

}
اگرچه کلاس ما Boeing737Drawingاز یک کلاس استاتیک ارث می برد، اما خود ثابت نیست! بنابراین همیشه به یک نمونه از کلاس خارجی نیاز خواهد داشت. ما می توانیم کلاس را Boeing737Drawingاز کلاس خارج کنیم Boeing737و آن را فقط یک کلاس عمومی کنیم. هیچ چیز تغییر نخواهد کرد - همچنین می تواند از یک تودرتو ایستا به ارث برسد 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;

}
تنها نکته مهم: در این مورد باید متغیر استاتیک را maxPassengersCountعمومی کنیم. اگر خصوصی بماند، کلاس عمومی عادی به آن دسترسی نخواهد داشت. ما کلاس های استاتیک را مرتب کرده ایم! :) حالا بریم سراغ کلاس های داخلی. همانطور که به یاد دارید، 3 نوع از آنها وجود دارد: کلاس های داخلی ساده، کلاس های محلی و کلاس های داخلی ناشناس. نمونه هایی از وراثت طبقات داخلی - 3دوباره بیایید از ساده به پیچیده برویم :)

کلاس های داخلی ناشناس

یک کلاس داخلی ناشناس نمی تواند از کلاس دیگری ارث ببرد. هیچ کلاس دیگری نمی تواند از یک کلاس ناشناس ارث ببرد. ساده تر از این نمی شد! :)

کلاس های محلی

کلاس های محلی (در صورتی که فراموش کرده باشید) در داخل یک بلوک کد کلاس دیگر اعلام می شوند. اغلب - در داخل برخی از روش های این کلاس خارجی. منطقی است که فقط کلاس های محلی دیگر در همان متد (یا بلوک) می توانند از یک کلاس محلی ارث ببرند. در اینجا یک مثال است:
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 валидации номера
   }
}
این کد از سخنرانی ما در مورد کلاس های محلی است. در داخل کلاس اعتبارسنجی شماره یک کلاس محلی داریم PhoneNumber- شماره تلفن. اگر برای اهداف خود نیاز به جداسازی دو نهاد جداگانه از آن داشته باشیم، به عنوان مثال، یک شماره تلفن همراه و یک شماره تلفن ثابت، فقط می توانیم این کار را در همان روش انجام دهیم. دلیل ساده است: محدوده یک کلاس محلی در متد (بلوک) جایی است که در آن اعلان شده است. بنابراین، ما قادر به استفاده خارجی (از جمله برای ارث) نخواهیم بود. با این حال، خود طبقه محلی امکانات بیشتری برای ارث بردن دارد! یک کلاس محلی می تواند از:
  1. کلاس معمولی
  2. یک طبقه درونی که در همان طبقه کلاس محلی یا در اجدادش اعلام شده است.
  3. از کلاس محلی دیگری که در همان متد اعلام شده است (block).
نکته اول و سوم بدیهی به نظر می رسد، اما دومی کمی گیج کننده است :/ بیایید به دو مثال نگاه کنیم. مثال 1 - "به ارث بردن یک کلاس محلی از یک کلاس داخلی که در همان کلاس کلاس محلی اعلام شده است":
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 валидации номера
   }
}
در اینجا ما کلاس را PhoneNumberاز متد خارج کرده validatePhoneNumber()و به جای محلی آن را داخلی کرده ایم. این مانع از آن نمی شود که 2 کلاس محلی خود را از آن به ارث ببریم. مثال 2 - "...یا در اجداد این طبقه." اینجاست که جالب تر می شود. PhoneNumberما می توانیم آن را حتی بالاتر از زنجیره ارث ببریم . بیایید یک طبقه انتزاعی را اعلام کنیم AbstractPhoneNumberValidatorکه جد ما خواهد شد 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;
       }
   }

}
همانطور که می بینید، ما نه تنها آن را اعلام کردیم، بلکه کلاس داخلی را نیز به آن منتقل کردیم PhoneNumber. با این حال، در کلاس نسل خود - PhoneNumberValidatorکلاس های محلی در متدها می توانند از 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 валидации номера
   }
}
به لطف ارتباط از طریق وراثت، طبقات محلی در داخل یک طبقه اولاد، طبقات درونی را در داخل جد "می بینند". و در آخر بریم سراغ گروه آخر :)

کلاس های داخلی

یک کلاس داخلی را می توان توسط کلاس داخلی دیگری که در همان کلاس بیرونی (یا نوادگان آن) اعلام شده است، به ارث برد. بیایید با استفاده از مثال دوچرخه خود از سخنرانی در کلاس های داخلی به این موضوع نگاه کنیم.
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
   }
}
Bicycleدر اینجا یک کلاس داخلی در داخل کلاس Seat- seat اعلام کردیم. نوع خاصی از صندلی های مسابقه از آن به ارث رسیده است - SportSeat. با این حال، می‌توانیم نوع جداگانه‌ای از "دوچرخه‌های مسابقه" ایجاد کنیم و آن را در یک کلاس جداگانه قرار دهیم:
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("Сидение опущено ниже!");
       }
   }
}
این نیز امکان پذیر است. طبقه درونی کودک ( SportBicycle.SportSeat) طبقات درونی اجداد را می بیند و می تواند از آنها ارث ببرد. ارث بردن از طبقات داخلی یک ویژگی بسیار مهم دارد! در دو نمونه قبلی SportSeatداخلی داشتیم. اما اگر تصمیم بگیریم آن را SportSeatبه یک کلاس عمومی معمولی تبدیل کنیم، که از طبقه داخلی نیز به ارث می رسد 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("Сидение опущено ниже!");
   }
}
ما یک خطا دریافت کردیم! آیا می توانید حدس بزنید با چه چیزی مرتبط است؟ :) ساده است. وقتی در مورد کلاس داخلی صحبت کردیم Bicycle.Seat، اشاره کردیم که سازنده کلاس داخلی به طور ضمنی یک ارجاع به یک شی از کلاس خارجی ارسال می کند. بنابراین، بدون ایجاد یک شی، Bicycleنمی توانید یک شی ایجاد کنید Seat. در مورد خلقت چطور SportSeat؟ مکانیسم داخلی مشابهی برای ارسال ضمنی ارجاع به یک شی کلاس خارجی در سازنده ندارد Seat. با این حال، بدون یک شی Bicycle، درست مانند مورد با Seat، ما نمی توانیم یک شی ایجاد کنیم SportSeat. بنابراین، ما تنها یک کار باقی مانده است که باید انجام دهیم - ارجاع صریح SportSeatبه شی به سازنده. Bicycleدر اینجا نحوه انجام آن آمده است:
class SportSeat extends Bicycle.Seat {

   public SportSeat(Bicycle bicycle) {

       bicycle.super();
   }

   public void up() {

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

   public void down() {

       System.out.println("Сидение опущено ниже!");
   }
}
برای این کار از یک کلمه خاص استفاده می کنیم super(); حالا، اگر بخواهیم یک شی بسازیم SportSeat، هیچ چیز ما را از انجام این کار باز نمی دارد:
public class Main {

   public static void main(String[] args) {

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

   }
}
وای، سخنرانی خیلی بزرگ بود :) اما چیزهای جدید زیادی یاد گرفتی! اکنون زمان حل چند مشکل است! :)
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION