JavaRush /Java blogi /Random-UZ /Mahalliy usulda ichki sinflar

Mahalliy usulda ichki sinflar

Guruhda nashr etilgan
Salom! Keling, ichki o'rnatilgan sinfning yana bir turi haqida gapiraylik. Ya'ni, mahalliy sinflar haqida (Metod mahalliy ichki sinflar). O'qishdan oldin eslab qolishingiz kerak bo'lgan birinchi narsa bu ularning o'rnatilgan sinflar tarkibidagi o'rni. Bizning diagrammamiz asosida biz mahalliy sinflar ichki sinflarning kichik turi ekanligini tushunishimiz mumkin, biz oldingi materiallardan biridaMahalliy usulda ichki sinflar - 2 batafsil gaplashdik . Biroq, mahalliy sinflar bir qator muhim xususiyatlarga va ichki sinflardan farqlarga ega. Kalit ularning deklaratsiyasida: Mahalliy sinf faqat kod blokida e'lon qilinadi. Ko'pincha - tashqi sinfning ba'zi usullari ichida. Masalan, u quyidagicha ko'rinishi mumkin:
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 валидации номера
   }
}
MUHIM!Agar sizda Java 7 o'rnatilgan bo'lsa IDEA ga qo'yilganda bu kod kompilyatsiya qilinmaydi.Buning sabablari haqida ma'ruza oxirida gaplashamiz. Bir so'z bilan aytganda, mahalliy sinflarning ishi til versiyasiga juda bog'liq. Agar ushbu kod siz uchun kompilyatsiya qilinmasa, siz IDEA-dagi til versiyasini Java 8 ga o'zgartirishingiz yoki finalusul parametriga so'z qo'shishingiz mumkin, shunda u quyidagicha ko'rinadi: validatePhoneNumber(final String number). Shundan so'ng hamma narsa ishlaydi. Bu kichik dastur - telefon raqamini tekshirish. Uning usuli validatePhoneNumber()kirish sifatida satrni oladi va bu telefon raqami yoki yo'qligini aniqlaydi. Va bu usul ichida biz mahalliy sinfimizni e'lon qildik PhoneNumber. Sizda mantiqiy savol tug'ilishi mumkin: nega? Nima uchun metod ichidagi sinfni e'lon qilish kerak? Nima uchun oddiy ichki sinfdan foydalanmaslik kerak? Darhaqiqat, buni qilish mumkin: sinfni PhoneNumberichki qilish. Yana bir narsa shundaki, yakuniy qaror dasturingizning tuzilishi va maqsadiga bog'liq. Keling, ichki sinflar haqidagi ma'ruzadagi misolimizni eslaylik:
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!");
       }
   }
}
Unda biz HandleBar(rulni) velosipedning ichki sinfini yaratdik. Nima farqi bor? Avvalo, sinfdan foydalanishda. Ikkinchi misoldagi sinf birinchisiga HandleBarqaraganda murakkabroq ob'ektdir . PhoneNumberBirinchidan, y HandleBarumumiy usullarga ega rightva left(setter va getter emas). Ikkinchidan, biz unga qayerda kerakligini va uning tashqi sinfini oldindan bashorat qila olmaymiz Bicycle- bu o'nlab turli xil joylar va usullar bo'lishi mumkin, hatto bitta dastur doirasida. Ammo sinf bilan PhoneNumberhamma narsa ancha sodda. Bizning dasturimiz juda oddiy. U faqat bitta funktsiyaga ega - raqam telefon raqami yoki yo'qligini tekshirish. Ko'pgina hollarda, bizniki PhoneNumberValidatorhatto mustaqil dastur bo'lmaydi, balki asosiy dastur uchun avtorizatsiya mantig'ining bir qismi bo'ladi. Masalan, turli veb-saytlarda ro'yxatdan o'tishda sizdan ko'pincha telefon raqamini kiritish so'raladi. Agar siz raqamlar o'rniga bema'ni narsalarni yozsangiz, sayt xato qiladi: "Bu telefon raqami emas!" Bunday saytning ishlashi uchun (aniqrog'i, foydalanuvchini avtorizatsiya qilish mexanizmi) uning ishlab chiquvchilari kodga bizning analogimizni kiritishlari mumkin PhoneNumberValidator. Boshqacha qilib aytadigan bo'lsak, bizda bitta usulga ega bo'lgan bitta tashqi sinf mavjud bo'lib, u dasturning bir joyida va boshqa hech qanday joyda qo'llanilmaydi. Va agar shunday bo'lsa, unda hech narsa o'zgarmaydi: bitta usul o'z vazifasini bajaradi - barchasi shu. Bunday holda, barcha ish mantig'i bitta usulda to'planganligi sababli, u erda qo'shimcha sinfni qamrab olish ancha qulayroq va to'g'ri bo'ladi. Uning getter va setterdan boshqa o'ziga xos usullari yo'q. Bizga asosan undan faqat konstruktor ma'lumotlari kerak. Boshqa usullarda qo'llanilmaydi. Shuning uchun, u haqida ma'lumotni u ishlatiladigan yagona usuldan tashqari kengaytirish uchun hech qanday sabab yo'q. Biz usulda mahalliy sinfni e'lon qilish misolini keltirdik, ammo bu yagona imkoniyat emas. Uni oddiygina kod blokida e'lon qilish mumkin:
public class PhoneNumberValidator {

   {
       class PhoneNumber {

           private String phoneNumber;

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

   }

   public void validatePhoneNumber(String phoneNumber) {


       //...code валидации номера
   }
}
Yoki hatto halqa ichida 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 валидации номера
   }
}
Ammo bunday holatlar juda kam uchraydi. Ko'pgina hollarda, deklaratsiya hali ham usul ichida sodir bo'ladi. Shunday qilib, biz e'lon bilan shug'ullandik, biz "falsafa" haqida ham gaplashdik :) Mahalliy sinflarning ichki sinflardan yana qanday xususiyatlari va farqlari bor? Mahalliy sinf ob'ektini u e'lon qilingan usul yoki blokdan tashqarida yaratish mumkin emas. generatePhoneNumber()Tasavvur qiling, bizga tasodifiy telefon raqamini yaratadigan va a ni qaytaradigan usul kerak PhoneNumber. Hozirgi vaziyatda biz validator sinfimizda bunday usulni yarata olmaymiz:
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() {

   }

}
Lokal sinflarning yana bir muhim xususiyati mahalliy o‘zgaruvchilar va metod parametrlariga kirish imkoniyatidir. Agar siz unutgan bo'lsangiz, "mahalliy" bu usul ichida e'lon qilingan o'zgaruvchidir. Ya'ni, agar biz ba'zi maqsadlarimiz uchun String russianCountryCodeusul ichida mahalliy o'zgaruvchini yaratsak validatePhoneNumber(), unga mahalliy sinfdan kirishimiz mumkin PhoneNumber. Biroq, bu erda dasturda ishlatiladigan tilning versiyasiga bog'liq bo'lgan juda ko'p nozikliklar mavjud. Ma'ruza boshida biz misollardan biridagi kod Java 7 da kompilyatsiya qilinmasligi mumkinligini eslatib o'tdik, esingizdami? Endi buning sabablarini ko'rib chiqamiz :) Java 7 da mahalliy sinf mahalliy o'zgaruvchiga yoki metod parametriga faqat metodda e'lon qilingan holda kirishi mumkin 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 валидации номера
}
Bu erda kompilyator ikkita xatoga yo'l qo'ydi. Ammo bu erda hamma narsa tartibda:
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 валидации номера
}
Endi siz ma'ruza boshida kod kompilyatsiya qilinmaganining sababini bilasiz: Java 7 da mahalliy sinf faqat final-metod parametrlari va final-local o'zgaruvchilarga kirish huquqiga ega. Java 8 da mahalliy sinflarning xatti-harakati o'zgardi. Tilning ushbu versiyasida mahalliy sinf nafaqat final-lokal o'zgaruvchilar va parametrlarga, balki effective-final. Effective-finalishga tushirilgandan beri qiymati o'zgarmagan o'zgaruvchidir. Masalan, Java 8 da biz o'zgaruvchini konsolga osongina ko'rsatishimiz mumkin russianCountryCode, garchi u bo'lmasa ham final. Asosiysi, u o'z ma'nosini o'zgartirmaydi. Ushbu misolda hamma narsa kerak bo'lganda ishlaydi:
public void validatePhoneNumber(String number) {

  String russianCountryCode = "+7";

    class PhoneNumber {

       public void printRussianCountryCode() {

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

    }

   //...code валидации номера
}
Ammo agar biz o'zgaruvchining qiymatini ishga tushirgandan so'ng darhol o'zgartirsak, kod kompilyatsiya qilinmaydi.
public void validatePhoneNumber(String number) {

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

    class PhoneNumber {

       public void printRussianCountryCode() {

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

    }

   //...code валидации номера
}
Ammo mahalliy sinf ichki sinfning kichik turi ekanligi bejiz emas! Ularning umumiy tomonlari ham bor. Mahalliy sinf tashqi sinfning barcha (hatto xususiy) maydonlari va usullariga kirish huquqiga ega: statik va statik bo'lmagan. Masalan, validator sinfimizga statik maydon qo'shamiz String phoneNumberRegex:
public class PhoneNumberValidator {

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

   public void validatePhoneNumber(String phoneNumber) {
       class PhoneNumber {

           //......
       }
   }
}
Tasdiqlash ushbu statik o'zgaruvchi yordamida amalga oshiriladi. Usul unga uzatilgan satrda oddiy iboraga mos kelmaydigan belgilar mavjudligini tekshiradi " [^0-9]" (ya'ni belgi 0 dan 9 gacha bo'lgan raqam emas). Ushbu o'zgaruvchiga mahalliy sinfdan osongina kira olamiz PhoneNumber. Masalan, oluvchini yozing:
public String getPhoneNumberRegex() {

   return phoneNumberRegex;
}
Mahalliy sinflar ichki sinflarga o'xshaydi, chunki ular hech qanday statik a'zolarni aniqlay olmaydi yoki e'lon qila olmaydi. Statik usullardagi mahalliy sinflar faqat qo'shuvchi sinfning statik a'zolariga murojaat qilishi mumkin. Misol uchun, agar siz qo'shuvchi sinfning o'zgaruvchisini (maydonini) statik deb belgilamasangiz, Java kompilyatori xato hosil qiladi: "Statik bo'lmagan o'zgaruvchiga statik kontekstdan murojaat qilib bo'lmaydi." Mahalliy sinflar statik emas, chunki ular o'z ichiga olgan blokning namuna a'zolariga kirish huquqiga ega. Shuning uchun ular statik deklaratsiyalarning ko'p turlarini o'z ichiga olmaydi. Siz blok ichidagi interfeysni e'lon qila olmaysiz; Interfeyslar tabiatan statikdir. Bu kod kompilyatsiya qilinmaydi:
public class PhoneNumberValidator {
   public static void validatePhoneNumber(String number) {
       interface I {}

       class PhoneNumber implements I{
           private String phoneNumber;

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

       //...code валидации номера
   }
}
Ammo agar interfeys tashqi sinf ichida e'lon qilingan bo'lsa, sinf PhoneNumberuni amalga oshirishi mumkin:
public class PhoneNumberValidator {
   interface I {}

   public static void validatePhoneNumber(String number) {

       class PhoneNumber implements I{
           private String phoneNumber;

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

       //...code валидации номера
   }
}
Mahalliy sinflar statik ishga tushiruvchilarni (boshlash bloklari) yoki interfeyslarni e'lon qila olmaydi. Ammo mahalliy sinflar doimiy o'zgaruvchilar ( ) bo'lishi sharti bilan statik a'zolarga ega bo'lishi mumkin static final. Ular shunday, mahalliy sinflar! Ko'rib turganingizdek, ular ichki sinflardan juda ko'p farqlarga ega. Ular qanday ishlashini tushunish uchun biz hatto til versiyasining xususiyatlariga sho'ng'ishimiz kerak edi :) Keyingi ma'ruzada biz anonim ichki sinflar - ichki o'rnatilgan sinflarning oxirgi guruhi haqida gapiramiz. O'qishlaringizga omad! :)
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION