CodeGym /جاوا بلاگ /Random-UR /مقامی طریقہ کار میں اندرونی کلاسز
John Squirrels
سطح
San Francisco

مقامی طریقہ کار میں اندرونی کلاسز

گروپ میں شائع ہوا۔
ہائے! آئیے ایک اور قسم کی نیسٹڈ کلاسز کے بارے میں بات کرتے ہیں۔ میں مقامی کلاسز (طریقہ-مقامی اندرونی کلاسز) کے بارے میں بات کر رہا ہوں۔ میں غوطہ لگانے سے پہلے، ہمیں پہلے نیسٹڈ کلاسوں کی ساخت میں ان کی جگہ کو یاد رکھنا چاہیے۔ مقامی طریقہ کار میں اندرونی کلاسز - 2ہمارے خاکے سے، ہم دیکھ سکتے ہیں کہ مقامی کلاسیں اندرونی کلاسوں کی ایک ذیلی قسم ہیں، جن کے بارے میں ہم نے پچھلے مواد میں تفصیل سے بات کی تھی ۔ تاہم، مقامی کلاسوں میں عام اندرونی کلاسوں سے کئی اہم خصوصیات اور فرق ہوتے ہیں۔ اہم بات ان کے اعلان میں ہے: مقامی کلاس کا اعلان صرف کوڈ کے بلاک میں کیا جاتا ہے۔ اکثر، یہ اعلان بیرونی طبقے کے کسی نہ کسی طریقے کے اندر ہوتا ہے۔ مثال کے طور پر، یہ اس طرح نظر آسکتا ہے:
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
   }
}
اہم!اگر آپ کے پاس Java 7 انسٹال ہے، تو IDEA میں چسپاں کرنے پر یہ کوڈ مرتب نہیں ہوگا۔ اس کی وجوہات کے بارے میں ہم سبق کے آخر میں بات کریں گے۔ مختصر یہ کہ مقامی کلاسیں کس طرح کام کرتی ہیں اس کا انحصار زبان کے ورژن پر ہے۔ اگر یہ کوڈ آپ کے لیے مرتب نہیں کرتا ہے، تو آپ یا تو IDEA میں زبان کے ورژن کو جاوا 8 میں تبدیل کر سکتے ہیں، یا لفظ کو finalمیتھڈ پیرامیٹر میں شامل کر سکتے ہیں تاکہ یہ اس طرح نظر آئے: validatePhoneNumber(final String number)۔ اس کے بعد، سب کچھ کام کرے گا. یہ ایک چھوٹا پروگرام ہے جو فون نمبروں کی توثیق کرتا ہے۔ اس کا validatePhoneNumber()طریقہ ان پٹ کے طور پر سٹرنگ لیتا ہے اور تعین کرتا ہے کہ آیا یہ فون نمبر ہے۔ اور اس طریقہ کے اندر، ہم نے اپنی مقامی PhoneNumberکلاس کا اعلان کیا۔ آپ معقول طور پر کیوں پوچھ سکتے ہیں۔ بالکل کیوں ہم ایک طریقہ کے اندر ایک کلاس کا اعلان کریں گے؟ ایک عام اندرونی طبقے کا استعمال کیوں نہیں کرتے؟ PhoneNumberیہ سچ ہے کہ ہم کلاس کو اندرونی کلاس بنا سکتے تھے ۔ لیکن حتمی حل آپ کے پروگرام کی ساخت اور مقصد پر منحصر ہے۔ آئیے اپنی مثال کو اندرونی کلاسوں کے سبق سے یاد کرتے ہیں:
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!");
       }
   }
}
اس میں، ہم نے HandleBarموٹر سائیکل کی ایک اندرونی کلاس بنائی۔ کیا فرق ہے؟ سب سے پہلے، کلاس کے استعمال کا طریقہ مختلف ہے۔ HandleBarدوسری مثال میں کلاس پہلی مثال میں کلاس سے زیادہ پیچیدہ ہستی ہے PhoneNumber۔ پہلے، HandleBarعوامی rightاور leftطریقے ہیں (یہ سیٹرز/گیٹر نہیں ہیں)۔ دوسرا، یہ پہلے سے اندازہ لگانا ناممکن ہے کہ ہمیں اس کی اور اس کے بیرونی Bicycleطبقے کی کہاں ضرورت ہو سکتی ہے۔ یہاں تک کہ ایک پروگرام میں بھی درجنوں مختلف مقامات اور طریقے ہوسکتے ہیں۔ لیکن PhoneNumberکلاس کے ساتھ، سب کچھ بہت آسان ہے. ہمارا پروگرام بہت آسان ہے۔ اس کا صرف ایک مقصد ہے: یہ چیک کرنا کہ آیا نمبر ایک درست فون نمبر ہے۔ زیادہ تر معاملات میں، ہمارا PhoneNumberValidatorاسٹینڈ اسٹون پروگرام بھی نہیں ہوگا، بلکہ بڑے پروگرام کے لیے اجازت کی منطق کا ایک حصہ ہوگا۔ مثال کے طور پر، جب صارفین سائن اپ کرتے ہیں تو مختلف ویب سائٹس اکثر فون نمبر مانگتی ہیں۔ اگر آپ نمبروں کے بجائے کچھ بکواس درج کرتے ہیں، تو ویب سائٹ ایک غلطی کی اطلاع دے گی: "یہ فون نمبر نہیں ہے!" PhoneNumberValidatorایسی ویب سائٹ کے ڈویلپرز (یا اس کے صارف کی اجازت کا طریقہ کار) اپنے کوڈ میں ہمارے جیسا کچھ شامل کر سکتے ہیں ۔ دوسرے لفظوں میں، ہمارے پاس ایک طریقہ کے ساتھ ایک آؤٹر کلاس ہے، جو پروگرام میں ایک جگہ استعمال ہوگی اور کہیں اور نہیں۔ اور اگر اسے استعمال کیا جائے تو اس میں کچھ بھی نہیں بدلے گا: ایک طریقہ اپنا کام کرتا ہے - اور بس۔ اس صورت میں، کیونکہ تمام منطق کو ایک طریقہ میں جمع کیا گیا ہے، یہ زیادہ آسان اور مناسب ہوگا کہ وہاں ایک اضافی کلاس کو سمیٹ لیا جائے۔ اس کا اپنا کوئی طریقہ نہیں ہے سوائے حاصل کرنے والے اور سیٹر کے۔ درحقیقت، ہمیں صرف کنسٹرکٹر سے ڈیٹا کی ضرورت ہے۔ یہ دوسرے طریقوں میں شامل نہیں ہے۔ اس کے مطابق، اس کے بارے میں صرف اس طریقہ سے باہر معلومات لینے کی کوئی وجہ نہیں ہے جہاں اسے استعمال کیا جاتا ہے۔ ہم نے ایک مثال بھی دی جس میں ایک طریقہ کار میں مقامی کلاس کا اعلان کیا جاتا ہے، لیکن یہ واحد آپشن نہیں ہے۔ اس کا اعلان صرف کوڈ بلاک میں کیا جا سکتا ہے:
public class PhoneNumberValidator {

   {
       class PhoneNumber {

           private String phoneNumber;

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

   }

   public void validatePhoneNumber(String phoneNumber) {


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

           // ...some logic
       }

       // ...number validation code
   }
}
لیکن ایسے معاملات انتہائی نایاب ہیں۔ زیادہ تر معاملات میں، اعلان طریقہ کے اندر ہو گا۔ لہذا، ہم نے اعلانات کا پتہ لگایا، اور ہم نے "فلسفہ" کے بارے میں بھی بات کی :) اندرونی کلاسوں کے مقابلے میں مقامی کلاسوں میں کیا اضافی خصوصیات اور اختلافات ہیں؟ مقامی کلاس کی کوئی چیز اس طریقہ یا بلاک سے باہر نہیں بنائی جا سکتی جس میں اسے قرار دیا گیا ہے۔ تصور کریں کہ ہمیں ایک ایسے generatePhoneNumber()طریقہ کی ضرورت ہے جو بے ترتیب فون نمبر تیار کرے اور کسی PhoneNumberچیز کو واپس کرے۔ ہماری موجودہ صورتحال میں، ہم اپنی validator کلاس میں ایسا طریقہ نہیں بنا سکتے:
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() {

   }

}
مقامی کلاسوں کی ایک اور اہم خصوصیت مقامی متغیرات اور طریقہ کار کے پیرامیٹرز تک رسائی کی صلاحیت ہے۔ اگر آپ بھول گئے ہیں تو، طریقہ کے اندر اعلان کردہ متغیر کو "مقامی" متغیر کہا جاتا ہے۔ یعنی اگر ہم کسی وجہ سے طریقہ کار String usCountryCodeکے اندر لوکل ویری ایبل بناتے ہیں validatePhoneNumber()تو ہم اسے لوکل PhoneNumberکلاس سے حاصل کر سکتے ہیں۔ تاہم، بہت ساری باریکیاں ہیں جو پروگرام میں استعمال ہونے والی زبان کے ورژن پر منحصر ہیں۔ سبق کے آغاز میں، ہم نے نوٹ کیا کہ مثالوں میں سے ایک کا کوڈ جاوا 7 میں مرتب نہیں ہو سکتا، یاد ہے؟ اب آئیے اس کی وجوہات پر غور کریں :) جاوا 7 میں، ایک مقامی کلاس مقامی متغیر یا طریقہ پیرامیٹر تک صرف اسی صورت میں رسائی حاصل کر سکتی ہے جب انہیں finalطریقہ کار کے مطابق قرار دیا گیا ہو۔
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
}
یہاں مرتب کرنے والا دو غلطیاں پیدا کرتا ہے۔ اور یہاں سب کچھ ترتیب میں ہے:
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
}
اب آپ جانتے ہیں کہ سبق کے آغاز کا کوڈ کیوں مرتب نہیں ہوتا ہے: جاوا 7 میں، ایک مقامی کلاس کو صرف finalمیتھڈ پیرامیٹرز اور finalمقامی متغیرات تک رسائی حاصل ہے۔ جاوا 8 میں، مقامی کلاسوں کا رویہ بدل گیا ہے۔ زبان کے اس ورژن میں، ایک مقامی کلاس کو نہ صرف finalمقامی متغیرات اور پیرامیٹرز تک رسائی حاصل ہوتی ہے، بلکہ ان تک بھی رسائی حاصل ہوتی ہے جو effective-final. Effective-finalایک متغیر ہے جس کی قیمت ابتدا کے بعد سے تبدیل نہیں ہوئی ہے۔ مثال کے طور پر، جاوا 8 میں، ہم کنسول پر متغیر کو آسانی سے ظاہر کر سکتے ہیں usCountryCode، چاہے یہ نہ ہو final۔ اہم بات یہ ہے کہ اس کی قدر تبدیل نہیں ہوتی۔ مندرجہ ذیل مثال میں، سب کچھ کام کرتا ہے جیسا کہ اسے ہونا چاہئے:
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
}
لیکن اگر ہم ابتدائی ہونے کے فوراً بعد متغیر کی قدر کو تبدیل کرتے ہیں تو کوڈ مرتب نہیں ہوگا۔
public void validatePhoneNumber(String number) {

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

    class PhoneNumber {

       public void printUsCountryCode() {

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

    }

   // ...number validation code
}
کوئی تعجب نہیں کہ ایک مقامی طبقہ اندرونی طبقے کے تصور کی ذیلی نسل ہے! ان میں مشترکہ خصوصیات بھی ہیں۔ ایک مقامی کلاس کو بیرونی طبقے کے تمام (یہاں تک کہ نجی) فیلڈز اور طریقوں تک رسائی حاصل ہے: جامد اور غیر جامد دونوں۔ مثال کے طور پر، آئیے String phoneNumberRegexاپنے validator کلاس میں ایک جامد فیلڈ شامل کریں:
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;
}
مقامی کلاسیں اندرونی کلاسوں سے ملتی جلتی ہیں، کیونکہ وہ کسی بھی جامد اراکین کی وضاحت یا اعلان نہیں کر سکتیں۔ جامد طریقوں میں مقامی کلاسیں صرف منسلک کلاس کے جامد اراکین کا حوالہ دے سکتی ہیں۔ مثال کے طور پر، اگر آپ منسلک کلاس کے متغیر (فیلڈ) کو جامد کے طور پر متعین نہیں کرتے ہیں، تو جاوا کمپائلر ایک خرابی پیدا کرتا ہے: "غیر جامد متغیر کو جامد سیاق و سباق سے حوالہ نہیں دیا جا سکتا۔" مقامی کلاسیں جامد نہیں ہیں، کیونکہ ان کو انکلوژنگ بلاک میں مثال کے ارکان تک رسائی حاصل ہے۔ نتیجے کے طور پر، وہ زیادہ تر قسم کے جامد اعلانات پر مشتمل نہیں ہو سکتے۔ آپ بلاک کے اندر انٹرفیس کا اعلان نہیں کر سکتے ہیں: انٹرفیس فطری طور پر جامد ہوتے ہیں۔ یہ کوڈ مرتب نہیں کرتا ہے:
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
   }
}
لیکن اگر کسی انٹرفیس کا اعلان بیرونی طبقے کے اندر کیا جاتا ہے، تو PhoneNumberکلاس اسے نافذ کر سکتی ہے:
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
   }
}
سٹیٹک انیشیلائزرز (ابتدائی بلاکس) یا انٹرفیس کا اعلان مقامی کلاسوں میں نہیں کیا جا سکتا۔ لیکن مقامی کلاسوں میں جامد اراکین ہو سکتے ہیں، بشرطیکہ وہ مستقل متغیر ہوں ( static final)۔ اور اب آپ مقامی کلاسوں کے بارے میں جانتے ہیں، لوگو! جیسا کہ آپ دیکھ سکتے ہیں، ان میں عام اندرونی طبقوں سے بہت فرق ہے۔ یہاں تک کہ ہمیں یہ سمجھنے کے لیے زبان کے مخصوص ورژنز کی خصوصیات کا جائزہ لینا پڑا کہ وہ کس طرح کام کرتے ہیں :) اگلے سبق میں، ہم گمنام اندرونی کلاسوں کے بارے میں بات کریں گے - نیسٹڈ کلاسوں کا آخری گروپ۔ آپ کی پڑھائی میں اچھی قسمت! :)
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION