CodeGym /Java Blog /Random /Mga panloob na klase sa isang lokal na pamamaraan
John Squirrels
Antas
San Francisco

Mga panloob na klase sa isang lokal na pamamaraan

Nai-publish sa grupo
Hi! Pag-usapan natin ang tungkol sa isa pang uri ng mga nested na klase. Pinag-uusapan ko ang tungkol sa mga lokal na klase (pamamaraan-lokal na mga panloob na klase). Bago sumisid, kailangan muna nating tandaan ang kanilang lugar sa istruktura ng mga nested classes. Mga panloob na klase sa isang lokal na pamamaraan - 2Mula sa aming diagram, makikita namin na ang mga lokal na klase ay isang subspecies ng mga panloob na klase, na pinag-usapan namin nang detalyado sa mga nakaraang materyales . Gayunpaman, ang mga lokal na klase ay may ilang mahahalagang katangian at pagkakaiba mula sa mga ordinaryong panloob na klase. Ang pangunahing bagay ay nasa kanilang deklarasyon: Ang isang lokal na klase ay idineklara lamang sa isang bloke ng code. Kadalasan, ang deklarasyon na ito ay nasa loob ng ilang paraan ng 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;
           }
       }

       // ...number validation code
   }
}
MAHALAGA!Kung mayroon kang naka-install na Java 7, hindi magko-compile ang code na ito kapag na-paste sa IDEA. Pag-uusapan natin ang mga dahilan nito sa pagtatapos ng aralin. Sa madaling salita, kung paano gumagana ang mga lokal na klase ay lubos na nakadepende sa bersyon ng wika. Kung hindi nag-compile para sa iyo ang code na ito, maaari mong ilipat ang bersyon ng wika sa IDEA sa Java 8, o idagdag ang salita finalsa parameter ng pamamaraan upang magmukhang ganito: validatePhoneNumber(final String number). Pagkatapos nito, gagana ang lahat. Ito ay isang maliit na programa na nagpapatunay sa mga 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, idineklara namin ang aming lokal PhoneNumberna klase. Maaaring makatuwirang itanong mo kung bakit. Bakit eksaktong idedeklara natin ang isang klase sa loob ng isang pamamaraan? Bakit hindi gumamit ng ordinaryong panloob na klase? Totoo, maaari naming gawin angPhoneNumberklase ng isang panloob na klase. Ngunit ang pangwakas na solusyon ay nakasalalay sa istraktura at layunin ng iyong programa. Alalahanin natin ang ating halimbawa mula sa isang aralin sa mga panloob na klase:

public class Bicycle {

   private String model;
   private int maxWeight;

   public Bicycle(String model, int maxWeight) {
       this.model = model;
       this.maxWeight = maxWeight;
   }
  
   public void start() {
       System.out.println("Let's go!");
   }

   public class HandleBar {

       public void right() {
           System.out.println("Steer right!");
       }

       public void left() {

           System.out.println("Steer left!");
       }
   }
}
Sa loob nito, gumawa kami HandleBarng inner class ng bike. Ano ang pinagkaiba? Una sa lahat, iba ang paraan ng paggamit ng klase. Ang HandleBarklase sa pangalawang halimbawa ay isang mas kumplikadong entity kaysa sa PhoneNumberklase sa unang halimbawa. Una, HandleBarmay pampubliko rightat leftmga pamamaraan (hindi ito setter/getters). Pangalawa, imposibleng mahulaan nang maaga kung saan natin ito maaaring kailanganin at ang panlabas Bicyclena uri nito. Maaaring mayroong dose-dosenang iba't ibang lugar at pamamaraan, kahit na sa isang programa. Ngunit sa PhoneNumberklase, ang lahat ay mas simple. Ang aming programa ay napaka-simple. Ito ay may isang layunin lamang: upang suriin kung ang isang numero ay isang wastong numero ng telepono. Sa karamihan ng mga kaso, ang amingPhoneNumberValidatoray hindi maging isang standalone na programa, ngunit isang bahagi ng lohika ng pahintulot para sa isang mas malaking programa. Halimbawa, madalas na humihingi ng numero ng telepono ang iba't ibang website kapag nag-sign up ang mga user. Kung maglalagay ka ng ilang kalokohan sa halip na mga numero, mag-uulat ang website ng isang error: "Hindi ito numero ng telepono!" Ang mga developer ng naturang website (o sa halip, ang mekanismo ng awtorisasyon ng user nito) ay maaaring magsama ng isang bagay na katulad ng sa aminPhoneNumberValidatorsa kanilang code. 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 ito ay ginamit, walang magbabago dito: isang paraan ang gumaganap nito — at iyon na. Sa kasong ito, dahil ang lahat ng lohika ay natipon sa isang paraan, ito ay magiging mas maginhawa at wastong mag-encapsulate ng karagdagang klase doon. Wala itong sariling pamamaraan maliban sa isang getter at setter. Sa katunayan, kailangan lang namin ng data mula sa constructor. Hindi ito kasangkot sa ibang mga pamamaraan. Alinsunod dito, walang dahilan upang kumuha ng impormasyon tungkol dito sa labas ng tanging paraan kung saan ito ginagamit. Nagbigay din kami ng isang halimbawa kung saan ang isang lokal na klase ay idineklara sa isang pamamaraan, ngunit hindi lamang ito ang opsyon. 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) {

      
       // ...number validation code
   }
}
O kahit sa forloop!

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;
               }
           }
          
           // ...some logic
       }

       // ...number validation code
   }
}
Ngunit ang mga ganitong kaso ay napakabihirang. Sa karamihan ng mga kaso, ang deklarasyon ay mangyayari sa loob ng pamamaraan. Kaya, naisip namin ang mga deklarasyon, at napag-usapan din namin ang tungkol sa "pilosopiya" :) Anong mga karagdagang tampok at pagkakaiba ang mayroon ang mga lokal na klase kumpara sa mga panloob na klase? Ang isang bagay ng isang lokal na klase ay hindi maaaring malikha sa labas ng pamamaraan o bloke kung saan ito idineklara. Isipin na kailangan namin ng isang generatePhoneNumber()paraan na bubuo ng random na numero ng telepono at magbabalik ng isang PhoneNumberbagay. Sa aming kasalukuyang sitwasyon, hindi kami makakagawa ng ganitong paraan sa aming validator class:

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;
           }
       }

       // ...number validation code
   }

   // Error! The compiler does not recognize the PhoneNumber class
   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 isang variable na idineklara sa loob ng isang pamamaraan ay kilala bilang isang "lokal" na variable. Iyon ay, kung lumikha tayo ng isang lokal String usCountryCodena variable sa loob ng validatePhoneNumber()pamamaraan sa ilang kadahilanan, maa-access natin ito mula sa lokal na PhoneNumberklase. Gayunpaman, mayroong maraming mga subtleties na nakasalalay sa bersyon ng wikang ginamit sa programa. Sa simula ng aralin, napansin namin na ang code para sa isa sa mga halimbawa ay maaaring hindi mag-compile sa Java 7, tandaan? Ngayon isaalang-alang natin ang mga dahilan para dito :) Sa Java 7, ang isang lokal na klase ay maaaring ma-access ang isang lokal na variable o parameter ng pamamaraan lamang kung sila ay idineklara tulad ng finalsa pamamaraan:

public void validatePhoneNumber(String number) {

   String usCountryCode = "+1";

   class PhoneNumber {

       private String phoneNumber;

       // Error! The method parameter must be declared as final!
       public PhoneNumber() {
           this.phoneNumber = number;
       }

       public void printUsCountryCode() {

           // Error! The local variable must be declared as final!
           System.out.println(usCountryCode);
       }

   }

   // ...number validation code
}
Dito bumubuo ang compiler ng dalawang error. At lahat ay maayos dito:

public void validatePhoneNumber(final String number) {

   final String usCountryCode = "+1";

    class PhoneNumber {

       private String phoneNumber;

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

       public void printUsCountryCode() {

           System.out.println(usCountryCode);
       }

    }

   // ...number validation code
}
Ngayon alam mo na kung bakit ang code mula sa simula ng aralin ay hindi mag-compile: sa Java 7, ang isang lokal na klase ay may access lamang sa mga finalparameter ng pamamaraan at finalmga lokal na variable. Sa Java 8, ang pag-uugali ng mga lokal na klase ay nagbago. Sa bersyong ito ng wika, ang isang lokal na klase ay may access hindi lamang sa finalmga lokal na variable at parameter, kundi pati na rin sa mga effective-final. Effective-finalay isang variable na ang halaga ay hindi nagbago mula noong inisyal. Halimbawa, sa Java 8, madali nating maipapakita ang usCountryCodevariable sa console, kahit na hindi ito final. Ang mahalaga ay hindi nagbabago ang halaga nito. Sa sumusunod na halimbawa, gumagana ang lahat ayon sa nararapat:

public void validatePhoneNumber(String number) {

  String usCountryCode = "+1";

    class PhoneNumber {

       public void printUsCountryCode() {

           // Java 7 would produce an error here
           System.out.println(usCountryCode);
       }

    }

   // ...number validation code
}
Ngunit kung babaguhin natin ang halaga ng variable kaagad pagkatapos ng pagsisimula, hindi magko-compile ang code.

public void validatePhoneNumber(String number) {

  String usCountryCode = "+1";
  usCountryCode = "+8";

    class PhoneNumber {

       public void printUsCountryCode() {

           // Error!
           System.out.println(usCountryCode);
       }

    }

   // ...number validation code
}
Hindi nakakagulat na ang lokal na klase ay isang subspecies ng konsepto ng inner class! Mayroon din silang mga karaniwang katangian. 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 String phoneNumberRegexna field sa aming validator class:

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 naipasa na string ay naglalaman ng mga character na hindi tumutugma sa karaniwang expression na " [^0-9]" (iyon ay, anumang character na hindi isang digit mula 0 hanggang 9). Madali nating maa-access ang variable na ito mula sa lokal PhoneNumberna klase. 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 error: "Hindi maaaring i-reference ang non-static na variable mula sa isang static na konteksto." Ang mga lokal na klase ay hindi static, dahil mayroon silang access sa mga miyembro ng instance sa kalakip na bloke. Bilang resulta, hindi sila maaaring maglaman ng karamihan sa mga uri ng mga static na deklarasyon. Hindi ka maaaring magdeklara ng isang interface sa loob ng isang bloke: ang mga interface ay likas na static. Ang code na ito ay hindi nag-compile:

public class PhoneNumberValidator {
   public static void validatePhoneNumber(String number) {
       interface I {}
      
       class PhoneNumber implements I{
           private String phoneNumber;

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

       // ...number validation 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;
           }
       }

       // ...number validation code
   }
}
Ang mga static na initializer (mga bloke ng pagsisimula) o mga interface ay hindi maaaring ideklara sa mga lokal na klase. 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). At ngayon alam mo na ang tungkol sa mga lokal na klase, mga kababayan! Tulad ng makikita mo, mayroon silang maraming pagkakaiba mula sa mga ordinaryong panloob na klase. Kinailangan pa naming suriin ang mga tampok ng mga partikular na bersyon ng wika upang maunawaan kung paano gumagana ang mga ito :) Sa susunod na aralin, pag-uusapan natin ang tungkol sa mga hindi kilalang panloob na klase — ang huling pangkat 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