JavaRush /Java Blog /Random-TL /Mga panloob na klase sa lokal na pamamaraan

Mga panloob na klase sa lokal na pamamaraan

Nai-publish sa grupo
Kamusta! Pag-usapan natin ang isa pang uri ng nested class. Lalo na, tungkol sa mga lokal na klase (Paraan ng mga lokal na panloob na klase). Ang unang bagay na kailangan mong tandaan bago mag-aral ay ang kanilang lugar sa istruktura ng mga nested na klase. Mga panloob na klase sa lokal na pamamaraan - 2Batay sa aming diagram, mauunawaan namin na ang mga lokal na klase ay isang subtype ng mga panloob na klase, na pinag-usapan namin nang detalyado sa isa sa mga nakaraang materyales . Gayunpaman, ang mga lokal na klase ay may ilang mahahalagang tampok at pagkakaiba mula sa mga panloob na klase. Ang susi ay nasa kanilang deklarasyon: Ang isang lokal na klase ay idineklara lamang sa isang bloke ng code. Kadalasan - sa loob ng ilang paraan ng isang panlabas na klase. Halimbawa, maaaring ganito ang hitsura nito:
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 валидации номера
   }
}
MAHALAGA!Ang code na ito ay hindi mag-iipon kapag na-paste sa IDEA kung mayroon kang naka-install na Java 7. Pag-uusapan natin ang mga dahilan nito sa pagtatapos ng lecture. Sa ilang salita, ang gawain ng mga lokal na klase ay lubos na nakadepende sa bersyon ng wika. Kung ang code na ito ay hindi nag-compile para sa iyo, maaari mong ilipat ang bersyon ng wika sa IDEA sa Java 8, o magdagdag ng salita finalsa parameter ng pamamaraan upang magmukhang ganito: validatePhoneNumber(final String number). Pagkatapos nito ay gagana ang lahat. Ito ay isang maliit na programa - isang validator ng numero ng telepono. Ang pamamaraan nito validatePhoneNumber()ay tumatagal ng isang string bilang input at tinutukoy kung ito ay isang numero ng telepono. At sa loob ng pamamaraang ito ay ipinahayag namin ang aming lokal na klase PhoneNumber. Maaaring mayroon kang lohikal na tanong: bakit? Bakit nagdedeklara ng isang klase sa loob ng isang pamamaraan? Bakit hindi gumamit ng regular na inner class? Sa katunayan, magagawa ito ng isa: gawing PhoneNumberpanloob ang klase. Ang isa pang bagay ay ang panghuling desisyon ay nakasalalay sa istraktura at layunin ng iyong programa. Tandaan natin ang ating halimbawa mula sa lecture tungkol sa mga panloob na klase:
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!");
       }
   }
}
Sa loob nito ginawa namin HandleBar(ang mga manibela) isang panloob na klase ng bike. Ano ang pinagkaiba? Una sa lahat, sa paggamit ng klase. Ang klase HandleBarmula sa pangalawang halimbawa ay isang mas kumplikadong entity kaysa PhoneNumbersa una. Una, ang y HandleBaray may mga pampublikong pamamaraan rightat left(hindi setter at getter). Pangalawa, hindi natin mahuhulaan nang maaga kung saan Bicyclenatin ito maaaring kailanganin at ang panlabas na klase nito - ito ay maaaring dose-dosenang iba't ibang lugar at pamamaraan, kahit na sa loob ng parehong programa. Ngunit sa isang klase PhoneNumberang lahat ay mas simple. Ang aming programa ay napaka-simple. Mayroon lamang itong isang function - upang suriin kung ang numero ay numero ng telepono. Sa karamihan ng mga kaso, ang sa amin PhoneNumberValidatoray hindi maging isang independiyenteng programa, ngunit isang bahagi lamang sa lohika ng pahintulot para sa pangunahing programa. Halimbawa, sa iba't ibang mga website, kapag nagrerehistro, madalas kang hihilingin na magpasok ng isang numero ng telepono. At kung nag-type ka ng ilang kalokohan sa halip na mga numero, magpapakita ang site ng isang error: "Hindi ito isang numero ng telepono!" Para sa pagpapatakbo ng naturang site (o sa halip, ang mekanismo ng awtorisasyon ng user), maaaring isama ng mga developer nito ang isang analogue namin sa code PhoneNumberValidator. Sa madaling salita, mayroon kaming isang panlabas na klase na may isang paraan na gagamitin sa isang lugar sa programa at wala saanman. At kung mangyayari ito, walang magbabago dito: isang paraan ang gumaganap nito - iyon lang. Sa kasong ito, dahil ang lahat ng lohika ng trabaho ay nakolekta sa isang paraan, magiging mas maginhawa at tama ang pag-encapsulate ng karagdagang klase doon. Wala itong sariling pamamaraan maliban sa getter at setter. Talagang kailangan lang namin ang data ng tagabuo mula dito. Hindi ito ginagamit sa ibang mga pamamaraan. Samakatuwid, walang dahilan upang palawakin ang impormasyon tungkol dito nang higit sa iisang paraan kung saan ito ginagamit. Nagbigay kami ng halimbawa ng pagdedeklara ng lokal na klase sa isang pamamaraan, ngunit hindi lang ito ang posibilidad. Maaari itong ipahayag nang simple sa isang bloke ng code:
public class PhoneNumberValidator {

   {
       class PhoneNumber {

           private String phoneNumber;

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

   }

   public void validatePhoneNumber(String phoneNumber) {


       //...code валидации номера
   }
}
O kahit sa isang loop 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 валидации номера
   }
}
Ngunit ang mga ganitong kaso ay napakabihirang. Sa karamihan ng mga kaso, ang deklarasyon ay magaganap pa rin sa loob ng pamamaraan. Kaya, hinarap namin ang anunsyo, napag-usapan din namin ang tungkol sa "pilosopiya" :) Ano ang iba pang mga tampok at pagkakaiba ng mga lokal na klase mula sa mga panloob na klase? Ang isang lokal na bagay ng klase ay hindi maaaring gawin sa labas ng pamamaraan o bloke kung saan ito idineklara. Isipin na kailangan namin ng isang paraan generatePhoneNumber()na bumubuo ng isang random na numero ng telepono at nagbabalik ng isang PhoneNumber. Hindi kami makakagawa ng ganoong paraan sa aming validator class sa kasalukuyang sitwasyon:
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() {

   }

}
Ang isa pang mahalagang tampok ng mga lokal na klase ay ang kakayahang ma-access ang mga lokal na variable at mga parameter ng pamamaraan. Kung sakaling nakalimutan mo, ang "lokal" ay isang variable na idineklara sa loob ng isang paraan. String russianCountryCodeIyon ay, kung gagawa tayo ng lokal na variable sa loob ng isang pamamaraan para sa ilan sa ating mga layunin validatePhoneNumber(), maa-access natin ito mula sa lokal na klase PhoneNumber. Gayunpaman, mayroong maraming mga subtleties dito na nakasalalay sa bersyon ng wikang ginamit sa programa. Sa simula ng lecture, gumawa kami ng tala na ang code sa isa sa mga halimbawa ay maaaring hindi mag-compile sa Java 7, tandaan? Ngayon tingnan natin ang mga dahilan para dito :) Sa Java 7, ang isang lokal na klase ay maaari lamang ma-access ang isang lokal na variable o parameter ng pamamaraan kung sila ay idineklara sa pamamaraan bilang 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 валидации номера
}
Dito naghagis ng dalawang error ang compiler. Ngunit narito ang lahat ay maayos:
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 валидации номера
}
Ngayon alam mo na ang dahilan kung bakit ang code sa simula ng lecture ay hindi nag-compile: ang isang lokal na klase sa Java 7 ay may access lamang sa final-method parameters at final-local variable. Sa Java 8, ang pag-uugali ng mga lokal na klase ay nagbago. Sa bersyong ito ng wika, ang lokal na klase ay may access hindi lamang sa final-local na mga variable at parameter, kundi pati na rin sa effective-final. Effective-finalay isang variable na ang halaga ay hindi nagbago mula noong inisyal. Halimbawa, sa Java 8 madali kaming makapagpapakita ng variable sa console russianCountryCode, kahit na hindi final. Ang pangunahing bagay ay hindi nito binabago ang kahulugan nito. Sa halimbawang ito, gumagana ang lahat ayon sa nararapat:
public void validatePhoneNumber(String number) {

  String russianCountryCode = "+7";

    class PhoneNumber {

       public void printRussianCountryCode() {

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

    }

   //...code валидации номера
}
Ngunit kung babaguhin natin ang halaga ng variable kaagad pagkatapos ng pagsisimula, hindi mag-compile ang code.
public void validatePhoneNumber(String number) {

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

    class PhoneNumber {

       public void printRussianCountryCode() {

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

    }

   //...code валидации номера
}
Ngunit hindi para sa wala na ang isang lokal na klase ay isang subtype ng isang panloob na klase! May common points din sila. Ang isang lokal na klase ay may access sa lahat (kahit pribado) na mga field at pamamaraan ng panlabas na klase: parehong static at non-static. Halimbawa, magdagdag tayo ng static na field sa ating validator class String phoneNumberRegex:
public class PhoneNumberValidator {

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

   public void validatePhoneNumber(String phoneNumber) {
       class PhoneNumber {

           //......
       }
   }
}
Isasagawa ang pagpapatunay gamit ang static na variable na ito. Sinusuri ng pamamaraan kung ang string na ipinasa dito ay naglalaman ng mga character na hindi tumutugma sa regular na expression na " [^0-9]" (iyon ay, ang character ay hindi isang numero mula 0 hanggang 9). Madali nating ma-access ang variable na ito mula sa lokal na klase PhoneNumber. Halimbawa, sumulat ng getter:
public String getPhoneNumberRegex() {

   return phoneNumberRegex;
}
Ang mga lokal na klase ay katulad ng mga panloob na klase dahil hindi nila matukoy o maipahayag ang anumang mga static na miyembro. Ang mga lokal na klase sa mga static na pamamaraan ay maaari lamang sumangguni sa mga static na miyembro ng kalakip na klase. Halimbawa, kung hindi mo tinukoy ang isang variable (field) ng kalakip na klase bilang static, ang Java compiler ay bubuo ng isang error: "Ang isang non-static na variable ay hindi maaaring i-reference mula sa isang static na konteksto." Ang mga lokal na klase ay hindi static dahil mayroon silang access sa mga miyembro ng instance ng naglalaman ng block. Samakatuwid, hindi maaaring maglaman ang mga ito ng karamihan sa mga uri ng mga static na deklarasyon. Hindi ka maaaring magdeklara ng interface sa loob ng isang bloke; Ang mga interface ay static sa kalikasan. Ang code na ito ay hindi mag-compile:
public class PhoneNumberValidator {
   public static void validatePhoneNumber(String number) {
       interface I {}

       class PhoneNumber implements I{
           private String phoneNumber;

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

       //...code валидации номера
   }
}
Ngunit kung ang isang interface ay idineklara sa loob ng isang panlabas na klase, PhoneNumbermaaaring ipatupad ito ng klase:
public class PhoneNumberValidator {
   interface I {}

   public static void validatePhoneNumber(String number) {

       class PhoneNumber implements I{
           private String phoneNumber;

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

       //...code валидации номера
   }
}
Ang mga lokal na klase ay hindi maaaring magdeklara ng mga static na initializer (mga bloke ng pagsisimula) o mga interface. Ngunit ang mga lokal na klase ay maaaring magkaroon ng mga static na miyembro, sa kondisyon na ang mga ito ay pare-pareho ang mga variable ( static final). Ganyan sila, mga lokal na klase! Tulad ng nakikita mo, marami silang pagkakaiba mula sa mga panloob na klase. Kinailangan pa naming sumisid sa mga feature ng bersyon ng wika para maunawaan kung paano gumagana ang mga ito :) Sa susunod na lecture, pag-uusapan natin ang tungkol sa mga hindi kilalang panloob na klase - ang huling grupo ng mga nested na klase. Good luck sa iyong pag-aaral! :)
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION