JavaRush /Java блогу /Random-KY /Уюшкан класстарды мурастоо

Уюшкан класстарды мурастоо

Группада жарыяланган
Салам! Бүгүн биз маанилүү механизмдин иштешин карап чыгабыз - уя класстардагы мурас. Башка класстан уяланган классты мурастоо керек болгондо эмне кыларыңызды ойлондуңуз беле, билбейм. Болбосо, мага ишениңиз: бул жагдай баш аламан болушу мүмкүн, анткени бул жерде көптөгөн нюанстар бар:
  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;
       }
   }
}
Келгиле, codeду өзгөртүүгө жана статикалык уя классты 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жалпыга ачык кылышыбыз керек. Эгер ал купуя бойдон калса, кадимки коомдук класс ага кире алbyte. Биз статикалык класстарды иреттеп алдык! :) Эми ички класстарга өтөлү. Эсиңизде болсо, алардын 3 түрү бар: жөн гана ички класстар, жергorктүү класстар жана анонимдүү ички класстар. Ички класстардын тукум куучулук мисалдары - 3Дагы, жөнөкөйдөн татаалга өтөлү :)

Анонимдүү ички класстар

Анонимдүү ички класс башка класстан мурастай алbyte. Башка эч бир класс анонимдүү класстан мурастай алbyte. Бул жөнөкөй болушу мүмкүн эмес! :)

Жергorктүү класстар

Жергorктүү класстар (эгер унутуп калсаңыз) башка класстын code блогунун ичинде жарыяланды. Көбүнчө - бул тышкы класстын кандайдыр бир ыкмасынын ичинде. Бир эле методдун (же блоктун) ичиндеги башка локалдык класстар гана локалдык класстан мурасталышы логикалык. Бул жерде бир мисал:
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 валидации номера
   }
}
Бул биздин жергorктүү класстар жөнүндөгү лекциябыздын codeу. Санды текшерүүчү класстын ичинде бизде жергorктүү класс бар PhoneNumber- телефон номери. Эгерде биздин максаттарыбыз үчүн андан эки башка an objectти, мисалы, уюлдук телефон номерин жана стационардык телефон номерин бөлүп алышыбыз керек болсо, биз муну бир эле ыкманын ичинде гана жасай алабыз. Себеби жөнөкөй: жергorктүү класстын масштабы ал жарыяланган методдун (блоктун) ичинде. Ошондуктан, биз кандайдыр бир жол менен аны сырттан (анын ичинде мурас үчүн) колдоно албайбыз. Бирок, жергorктүү класстын өзү мурастоо үчүн кеңири мүмкүнчүлүктөргө ээ! Жергorктүү класс төмөнкүдөн мураска алат:
  1. Кадимки класс.
  2. Жергorктүү класс менен бир класста же анын ата-бабаларында жарыяланган ички класс.
  3. Ушул эле ыкма менен жарыяланган башка жергorктүү класстан (блок).
Биринчи жана үчүнчү пункттар ачык көрүнүп турат, бирок экинчиси бир аз түшүнүксүз :/ Келгиле, эки мисалды карап көрөлү. Мисал 1 - "жергorктүү класс менен бир класста жарыяланган ички класстан жергorктүү классты мурастоо":
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(), аны жергorктүү эмес, ички кылдык. Бул биздин жергorктүү 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- методдордогу жергorктүү класстар 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 валидации номера
   }
}
Мурас аркылуу байланыштын аркасында урпак классынын ичиндеги жергorктүү класстар ата-бабанын ичиндеги ички класстарды “көрүшөт”. Акыры, акыркы топко өтөлү :)

Ички класстар

Ички класс ошол эле сырткы класста (же анын тукумунда) жарыяланган башка ички класс тарабынан мурасталышы мүмкүн. Келгиле, муну ички класстар жөнүндөгү лекциядагы велосипеддин мисалында карап көрөлү.
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- отургуч. Жарыш отургучтарынын өзгөчө түрү андан тукум кууп өткөн - 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, ички класстын конструктору сырткы класстын an objectисине шилтемени кыйыр түрдө өткөрөрүн айттык. Демек, an object түзбөй туруп, Bicyclean objectти түзө албайсыз Seat. Жаратуу жөнүндө эмне айтууга болот SportSeat? Анын конструктордогу тышкы класс an objectисине шилтемени кыйыр түрдө берүү үчүн орнотулган механизми жок Seat. Бирок, an objectсиз Bicycle, мисалы Seat, an objectисин түзө албайбыз SportSeat. Ошондуктан, бизде бир гана нерсе калды - SportSeatan objectке шилтемени конструкторго 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(); Now, эгерде биз an object түзгүбүз келсе 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