JavaRush /Java блогы /Random-KK /Кірістірілген класстардың тұқым қуалауы

Кірістірілген класстардың тұқым қуалауы

Топта жарияланған
Сәлеметсіз бе! Бүгін біз маңызды механизмнің жұмысын қарастырамыз - кірістірілген сыныптардағы мұрагерлік. Кірістірілген сыныпты басқа біреуден мұрагер ету қажет болғанда не істеу керектігі туралы ойланбағаныңызды білмеймін. Егер жоқ болса, маған сеніңіз: бұл жағдай шатастыруы мүмкін, өйткені мұнда көптеген нюанстар бар:
  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Тағы да қарапайымнан күрделіге көшейік :)

Анонимді ішкі сыныптар

Анонимді ішкі класс басқа сыныптан мұра ала алмайды. Ешбір басқа класс анонимді сыныптан мұра ете алмайды. Бұл қарапайым болуы мүмкін емес! :)

Жергілікті сыныптар

Жергілікті сыныптар (ұмытып кеткен жағдайда) басқа сыныптың 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 валидации номера
   }
}
Бұл жергілікті сыныптар туралы лекциямыздың codeы. Санды валидатор класының ішінде бізде жергілікті класс PhoneNumber- телефон нөмірі бар. Егер біздің мақсаттарымыз үшін одан екі бөлек нысанды, мысалы, ұялы телефон нөмірін және стационарлық телефон нөмірін бөлу қажет болса, біз мұны бір әдіспен ғана жасай аламыз. Себебі қарапайым: жергілікті сыныптың көлемі ол жарияланған әдіс (блок) ішінде болады. Сондықтан біз оны қандай да бір түрде сырттан (соның ішінде мұрагерлік үшін) пайдалана алмаймыз. Дегенмен, жергілікті сыныптың мұрагерлік мүмкіндіктері кеңірек! Жергілікті класс келесіден мұра алады:
  1. Кәдімгі сынып.
  2. Жергілікті класспен бір сыныпта немесе оның ата-бабаларында жарияланған ішкі класс.
  3. Сол әдісте (блокта) жарияланған басқа жергілікті сыныптан.
Бірінші және үшінші нүктелер анық көрінеді, бірақ екіншісі аздап түсініксіз :/ Екі мысалды қарастырайық. 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, ішкі класстың конструкторы сыртқы сыныптың an objectісіне сілтемені жасырын түрде беретінін айттық. Сондықтан, нысанды жасамай, Bicycleнысанды жасай алмайсыз Seat. Ал жаратылыс туралы не деуге болады SportSeat? Оның конструктордағы сыртқы сынып нысанына сілтемені жасырын түрде жіберуге арналған кірістірілген механизмі жоқ Seat. Дегенмен, нысансыз Bicycle, мысалы, сияқты Seat, біз нысан жасай алмаймыз 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