JavaRush /Java блогы /Random-KK /Жергілікті әдіс бойынша ішкі сыныптар

Жергілікті әдіс бойынша ішкі сыныптар

Топта жарияланған
Сәлеметсіз бе! Енді кірістірілген сыныптың басқа түрі туралы сөйлесейік. Атап айтқанда, жергілікті сыныптар туралы (Метод жергілікті ішкі сыныптар). Оқудан бұрын есте сақтау керек бірінші нәрсе - олардың кірістірілген сыныптар құрылымындағы орны. Жергілікті әдіс бойынша ішкі сыныптар – 2Біздің диаграммамызға сүйене отырып, біз жергілікті сыныптардың ішкі сыныптардың ішкі түрі екенін түсінуге болады, біз бұл туралы алдыңғы материалдардың бірінде егжей-тегжейлі айтқанбыз . Дегенмен, жергілікті сыныптардың ішкі сыныптардан бірқатар маңызды ерекшеліктері мен айырмашылықтары бар. Кілт олардың декларациясында: Жергілікті класс тек code блогында жарияланады. Көбінесе - сыртқы сыныптың кейбір әдістерінің ішінде. Мысалы, ол келесідей болуы мүмкін:
public class PhoneNumberValidator {

   public void validatePhoneNumber(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;
           }
       }

       //...code валидации номера
   }
}
МАҢЫЗДЫ!Егер сізде Java 7 орнатылған болса, бұл code IDEA-ға қойылған кезде компиляцияланбайды.Оның себептері туралы дәріс соңында айтамыз. Бір сөзбен айтқанда, жергілікті сыныптардың жұмысы тілдік нұсқаға өте тәуелді. Егер бұл code сіз үшін құрастырылмаса, сіз IDEA жүйесіндегі тіл нұсқасын Java 8 нұсқасына ауыстыра аласыз немесе finalәдіс параметріне келесідей етіп сөз қоса аласыз: validatePhoneNumber(final String number). Осыдан кейін бәрі жұмыс істейді. Бұл шағын бағдарлама - телефон нөмірін тексеруші. Оның әдісі validatePhoneNumber()жолды енгізу ретінде қабылдайды және оның телефон нөмірі екенін анықтайды. Бұл әдістің ішінде біз жергілікті классымызды жарияладық PhoneNumber. Сізде логикалық сұрақ туындауы мүмкін: неге? Неліктен әдіс ішіндегі сыныпты жариялау керек? Неліктен әдеттегі ішкі сыныпты пайдаланбасқа? Шынында да, мұны істеуге болады: сыныпты PhoneNumberішкі етіп жасаңыз. Тағы бір нәрсе, соңғы шешім сіздің бағдарламаңыздың құрылымы мен мақсатына байланысты. Ішкі сыныптар туралы лекциядағы мысалды еске түсірейік:
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!");
   }

   public class HandleBar {

       public void right() {
           System.out.println("Steering wheel to the right!");
       }

       public void left() {

           System.out.println("Steering wheel to the left!");
       }
   }
}
Онда біз HandleBar(тұтқа) велосипедтің ішкі класын жасадық. Айырмашылығы неде? Ең алдымен, сыныпты пайдалануда. Екінші мысалдағы сынып біріншіге HandleBarқарағанда күрделірек нысан . PhoneNumberБіріншіден, y-ның HandleBarжалпы әдістері бар rightжәне left(қоюшы және алушы емес). Екіншіден, біз оның қай жерде қажет болатынын және оның сыртқы класын алдын ала болжай алмаймыз Bicycle- бұл тіпті бір бағдарламаның ішінде ондаған әртүрлі орындар мен әдістер болуы мүмкін. Бірақ сыныппен PhoneNumberбәрі әлдеқайда қарапайым. Біздің бағдарлама өте қарапайым. Оның бір ғана функциясы бар - нөмірдің телефон нөмірі екенін тексеру. Көп жағдайда біздікі PhoneNumberValidatorтіпті тәуелсіз бағдарлама емес, негізгі бағдарлама үшін авторизация логикасының бір бөлігі ғана болады. Мысалы, әртүрлі веб-сайттарда тіркелу кезінде жиі телефон нөмірін енгізу сұралады. Егер сіз сандардың орнына мағынасыз сөздерді терсеңіз, сайт қатені көрсетеді: «Бұл телефон нөмірі емес!» Мұндай сайттың жұмыс істеуі үшін (дәлірек айтқанда, пайдаланушыны авторизациялау механизмі) оны әзірлеушілер codeқа біздің аналогымызды қоса алады PhoneNumberValidator. Басқаша айтқанда, бізде бір әдіс бар бір сыртқы сынып бар, ол бағдарламада бір жерде және басқа еш жерде қолданылмайтын болады. Егер солай болса, онда ештеңе өзгермейді: бір әдіс өз жұмысын жасайды - бұл бәрі. Бұл жағдайда барлық жұмыс логикасы бір әдісте жинақталғандықтан, онда қосымша сыныпты инкапсуляциялау әлдеқайда ыңғайлы және дұрыс болады. Оның гетер мен сетерден басқа өз әдістері жоқ. Бізге тек конструктор деректері қажет. Ол басқа әдістерде қолданылмайды. Сондықтан ол туралы ақпаратты ол қолданылатын жалғыз әдістен тыс кеңейтуге ешқандай себеп жоқ. Біз жергілікті классты әдісте жариялаудың мысалын келтірдік, бірақ бұл жалғыз мүмкіндік емес. Оны codeтық блокта жай ғана жариялауға болады:
public class PhoneNumberValidator {

   {
       class PhoneNumber {

           private String phoneNumber;

           public PhoneNumber(String phoneNumber) {
               this.phoneNumber = phoneNumber;
           }
       }

   }

   public void validatePhoneNumber(String phoneNumber) {


       //...code валидации номера
   }
}
Немесе тіпті циклде for!
public class PhoneNumberValidator {


   public void validatePhoneNumber(String phoneNumber) {

       for (int i = 0; i < 10; i++) {

           class PhoneNumber {

               private String phoneNumber;

               public PhoneNumber(String phoneNumber) {
                   this.phoneNumber = phoneNumber;
               }
           }

           //...Howая-то логика
       }

       //...code валидации номера
   }
}
Бірақ мұндай жағдайлар өте сирек кездеседі. Көп жағдайда декларация әлі де әдіс ішінде болады. Сонымен, біз хабарландырумен айналыстық, біз «философия» туралы да сөйлестік :) Жергілікті сыныптардың ішкі сыныптардан тағы қандай ерекшеліктері мен айырмашылығы бар? Жергілікті сынып нысанын ол жарияланған әдіс немесе блоктан тыс жасау мүмкін емес. generatePhoneNumber()Бізге кездейсоқ телефон нөмірін жасайтын және қайтаратын әдіс қажет деп елестетіңіз PhoneNumber. Біз қазіргі жағдайда валидатор сыныбымызда мұндай әдісті жасай алмаймыз:
public class PhoneNumberValidator {

   public void validatePhoneNumber(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;
           }
       }

       //...code валидации номера
   }

   //ошибка! компилятор не понимает, что это за класс - PhoneNumber
   public PhoneNumber generatePhoneNumber() {

   }

}
Жергілікті класстардың тағы бір маңызды ерекшелігі жергілікті айнымалылар мен әдіс параметрлеріне қол жеткізу мүмкіндігі болып табылады. Егер сіз ұмытып қалсаңыз, «жергілікті» - әдіс ішінде жарияланған айнымалы. Яғни, егер біз кейбір мақсаттарымыз үшін String russianCountryCodeәдіс ішінде жергілікті айнымалыны жасасақ validatePhoneNumber(), біз оған жергілікті сыныптан қол жеткізе аламыз PhoneNumber. Дегенмен, мұнда бағдарламада қолданылатын тілдің нұсқасына байланысты көптеген нәзіктіктер бар. Дәрістің басында біз мысалдардың біріндегі code Java 7-де компиляцияланбауы мүмкін екенін ескерттік, есіңізде ме? Енді мұның себептерін қарастырайық :) Java 7-де жергілікті класс жергілікті айнымалыға немесе әдіс параметріне, егер олар әдісте ретінде жарияланған болса ғана қол жеткізе алады final:
public void validatePhoneNumber(String number) {

   String russianCountryCode = "+7";

   class PhoneNumber {

       private String phoneNumber;

       //ошибка! параметр метода должен быть объявлен How final!
       public PhoneNumber() {
           this.phoneNumber = number;
       }

       public void printRussianCountryCode() {

           //ошибка! локальная переменная должна быть объявлена How final!
           System.out.println(russianCountryCode);
       }

   }

   //...code валидации номера
}
Мұнда компилятор екі қате жіберді. Бірақ мұнда бәрі тәртіппен:
public void validatePhoneNumber(final String number) {

   final String russianCountryCode = "+7";

    class PhoneNumber {

       private String phoneNumber;


       public PhoneNumber() {
           this.phoneNumber = number;
       }

       public void printRussianCountryCode() {

           System.out.println(russianCountryCode);
       }

    }

   //...code валидации номера
}
Енді сіз дәрістің басындағы codeтың компиляцияланбау себебін білесіз: Java 7-дегі жергілікті сынып тек final-метод параметрлеріне және final-жергілікті айнымалыларға қол жеткізе алады. Java 8-де жергілікті сыныптардың әрекеті өзгерді. Тілдің бұл нұсқасында жергілікті класс тек final-local айнымалылар мен параметрлерге ғана емес, сонымен қатар effective-final. Effective-finalинициализациядан бері мәні өзгермеген айнымалы болып табылады. Мысалы, Java 8-де біз айнымалы мәнді консольге оңай көрсете аламыз russianCountryCode, тіпті егер ол болмаса да final. Ең бастысы, оның мағынасы өзгермейді. Бұл мысалда бәрі қажетінше жұмыс істейді:
public void validatePhoneNumber(String number) {

  String russianCountryCode = "+7";

    class PhoneNumber {

       public void printRussianCountryCode() {

           //в Java 7 здесь была бы ошибка
           System.out.println(russianCountryCode);
       }

    }

   //...code валидации номера
}
Бірақ айнымалының мәнін инициализациядан кейін бірден өзгертсек, code компиляцияланбайды.
public void validatePhoneNumber(String number) {

  String russianCountryCode = "+7";
  russianCountryCode = "+8";

    class PhoneNumber {

       public void printRussianCountryCode() {

           //error!
           System.out.println(russianCountryCode);
       }

    }

   //...code валидации номера
}
Бірақ жергілікті класс ішкі сыныптың ішкі түрі деп бекер айтылмаған! Олардың ортақ тұстары да бар. Жергілікті класс сыртқы сыныптың барлық (тіпті жеке) өрістері мен әдістеріне қол жеткізе алады: статикалық және статикалық емес. Мысалы, валидатор сыныбына статикалық өрісті қосамыз String phoneNumberRegex:
public class PhoneNumberValidator {

   private static String phoneNumberRegex = "[^0-9]";

   public void validatePhoneNumber(String phoneNumber) {
       class PhoneNumber {

           //......
       }
   }
}
Тексеру осы статикалық айнымалы арқылы орындалады. Әдіс оған берілген жолда тұрақты өрнекке сәйкес келмейтін таңбалардың бар-жоғын тексереді " [^0-9]" (яғни таңба 0-ден 9-ға дейінгі сан емес). Біз бұл айнымалыға жергілікті сыныптан оңай қол жеткізе аламыз PhoneNumber. Мысалы, алушыны жазыңыз:
public String getPhoneNumberRegex() {

   return phoneNumberRegex;
}
Жергілікті сыныптар ішкі сыныптарға ұқсас, себебі олар кез келген статикалық мүшелерді анықтай немесе жариялай алмайды. Статикалық әдістердегі жергілікті сыныптар тек қоршау класының статикалық мүшелеріне сілтеме жасай алады. Мысалы, егер сіз қоршау класының айнымалы мәнін (өрісін) статикалық ретінде анықтамасаңыз, Java компиляторы қатені жасайды: «Статикалық емес айнымалыға статикалық контекстен сілтеме жасау мүмкін емес». Жергілікті сыныптар статикалық емес, себебі оларда блоктың дана мүшелеріне қатынасу мүмкіндігі бар. Сондықтан олар статикалық мәлімдемелердің көпшілігін қамти алмайды. Блок ішіндегі интерфейсті жариялай алмайсыз; Интерфейстердің табиғаты статикалық. Бұл code компиляцияланбайды:
public class PhoneNumberValidator {
   public static void validatePhoneNumber(String number) {
       interface I {}

       class PhoneNumber implements I{
           private String phoneNumber;

           public PhoneNumber() {
               this.phoneNumber = number;
           }
       }

       //...code валидации номера
   }
}
Бірақ егер интерфейс сыртқы сынып ішінде жарияланған болса, сынып PhoneNumberоны жүзеге асыра алады:
public class PhoneNumberValidator {
   interface I {}

   public static void validatePhoneNumber(String number) {

       class PhoneNumber implements I{
           private String phoneNumber;

           public PhoneNumber() {
               this.phoneNumber = number;
           }
       }

       //...code валидации номера
   }
}
Жергілікті сыныптар статикалық инициализаторларды (инициализация блоктары) немесе интерфейстерді жариялай алмайды. Бірақ жергілікті сыныптарда тұрақты айнымалылар ( ) болған жағдайда статикалық мүшелер болуы мүмкін static final. Міне, олар, жергілікті сыныптар! Көріп отырғаныңыздай, олардың ішкі сыныптардан көптеген айырмашылықтары бар. Біз тіпті олардың қалай жұмыс істейтінін түсіну үшін тілдік нұсқаның мүмкіндіктеріне сүңгуге тура келді :) Келесі лекцияда біз анонимді ішкі сыныптар - кірістірілген сыныптардың соңғы тобы туралы айтатын боламыз. Оқуларыңызға сәттілік! :)
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION