CodeGym /جاوا بلاگ /Random-UR /Reflection API: عکاسی۔ جاوا کا تاریک پہلو
John Squirrels
سطح
San Francisco

Reflection API: عکاسی۔ جاوا کا تاریک پہلو

گروپ میں شائع ہوا۔
سلام، نوجوان پڈاون۔ اس مضمون میں، میں آپ کو فورس کے بارے میں بتاؤں گا، ایک ایسی طاقت جسے جاوا پروگرامرز صرف بظاہر ناممکن حالات میں استعمال کرتے ہیں۔ جاوا کا تاریک پہلو Reflection API ہے۔ جاوا میں، جاوا ریفلیکشن API کا استعمال کرتے ہوئے عکاسی کو لاگو کیا جاتا ہے۔

جاوا ریفلیکشن کیا ہے؟

انٹرنیٹ پر ایک مختصر، درست اور مقبول تعریف ہے۔ ریفلیکشن ( دیر سے لاطینی reflexio - واپس جانے کے لیے ) ایک طریقہ کار ہے جس کے چلنے کے دوران کسی پروگرام کے بارے میں ڈیٹا کو دریافت کیا جاتا ہے۔ عکاسی آپ کو فیلڈز، طریقوں اور کلاس کنسٹرکٹرز کے بارے میں معلومات کو دریافت کرنے دیتی ہے۔ ریفلیکشن آپ کو ان اقسام کے ساتھ کام کرنے دیتا ہے جو کمپائل کے وقت موجود نہیں تھیں، لیکن جو رن ٹائم کے دوران دستیاب ہوئیں۔ خامی کی معلومات جاری کرنے کے لیے عکاسی اور منطقی طور پر مسلسل ماڈل درست ڈائنامک کوڈ بنانا ممکن بناتا ہے۔ دوسرے لفظوں میں، یہ سمجھنا کہ جاوا میں عکاسی کیسے کام کرتی ہے آپ کے لیے بہت سے حیرت انگیز مواقع کھولے گی۔ آپ کلاسوں اور ان کے اجزاء کو لفظی طور پر جگا سکتے ہیں۔ یہاں ایک بنیادی فہرست ہے جو عکاسی کی اجازت دیتا ہے:
  • کسی چیز کی کلاس سیکھیں/تعین کریں؛
  • کلاس کے موڈیفائرز، فیلڈز، طریقے، مستقل، کنسٹرکٹرز اور سپر کلاسز کے بارے میں معلومات حاصل کریں۔
  • معلوم کریں کہ کون سے طریقے نافذ شدہ انٹرفیس سے تعلق رکھتے ہیں؛
  • ایک ایسی کلاس کی مثال بنائیں جس کی کلاس کا نام رن ٹائم تک نامعلوم ہو؛
  • نام سے کسی چیز کے فیلڈز کی قدریں حاصل کریں اور سیٹ کریں۔
  • کسی چیز کے طریقہ کو نام سے کال کریں۔
ریفلیکشن تقریباً تمام جدید جاوا ٹیکنالوجیز میں استعمال ہوتا ہے۔ یہ تصور کرنا مشکل ہے کہ جاوا، ایک پلیٹ فارم کے طور پر، بغیر کسی عکاسی کے اتنی وسیع پیمانے پر اپنائیت حاصل کر سکتا تھا۔ سب سے زیادہ امکان، یہ نہیں ہوگا. اب جب کہ آپ عام طور پر ایک نظریاتی تصور کے طور پر عکاسی سے واقف ہیں، آئیے اس کے عملی اطلاق کی طرف بڑھتے ہیں! ہم Reflection API کے تمام طریقے نہیں سیکھیں گے — صرف وہی جو آپ کو عملی طور پر درپیش ہوں گے۔ چونکہ عکاسی میں کلاسوں کے ساتھ کام کرنا شامل ہے، اس لیے ہم ایک سادہ کلاس کے ساتھ شروع کریں گے جس کا نام ہے MyClass:
public class MyClass {
   private int number;
   private String name = "default";
//    public MyClass(int number, String name) {
//        this.number = number;
//        this.name = name;
//    }
   public int getNumber() {
       return number;
   }
   public void setNumber(int number) {
       this.number = number;
   }
   public void setName(String name) {
       this.name = name;
   }
   private void printData(){
       System.out.println(number + name);
   }
}
جیسا کہ آپ دیکھ سکتے ہیں، یہ ایک بہت ہی بنیادی کلاس ہے۔ پیرامیٹرز کے ساتھ کنسٹرکٹر کو جان بوجھ کر تبصرہ کیا گیا ہے۔ ہم اس پر بعد میں واپس آئیں گے۔ اگر آپ نے کلاس کے مواد کو غور سے دیکھا، تو آپ نے شاید نام کے فیلڈ کے لیے حاصل کرنے والے کی غیر موجودگی کو دیکھا۔ نام کی فیلڈ کو ہی پرائیویٹ ایکسیس موڈیفائر کے ساتھ نشان زد کیا گیا ہے: ہم کلاس سے باہر اس تک رسائی حاصل نہیں کر سکتے جس کا مطلب ہے کہ ہم اس کی قدر کو بازیافت نہیں کر سکتے۔ " تو کیا مسئلہ ہے ؟" تم کہو. "ایک حاصل کرنے والا شامل کریں یا رسائی موڈیفائر کو تبدیل کریں"۔ اور آپ درست کہیں گے، جب تک کہ مرتب کردہ AAR لائبریری میں نہ ہو یا کسی اور نجی ماڈیول میں تبدیلیاں کرنے کی صلاحیت نہ ہو۔ عملی طور پر، یہ ہر وقت ہوتا ہے. اور کچھ لاپرواہ پروگرامر صرف ایک گیٹر لکھنا بھول گئے ۔ یہ عکاسی کو یاد کرنے کا بہت وقت ہے! آئیے کلاس کے نجی نام والے فیلڈ میں جانے کی کوشش کریں: MyClassMyClass
public static void main(String[] args) {
   MyClass myClass = new MyClass();
   int number = myClass.getNumber();
   String name = null; // No getter =(
   System.out.println(number + name); // Output: 0null
   try {
       Field field = myClass.getClass().getDeclaredField("name");
       field.setAccessible(true);
       name = (String) field.get(myClass);
   } catch (NoSuchFieldException | IllegalAccessException e) {
       e.printStackTrace();
   }
   System.out.println(number + name); // Output: 0default
}
آئیے تجزیہ کرتے ہیں کہ ابھی کیا ہوا ہے۔ جاوا میں، نامی ایک شاندار کلاس ہے Class۔ یہ ایک قابل عمل جاوا ایپلی کیشن میں کلاسز اور انٹرفیس کی نمائندگی کرتا ہے۔ Classہم اور کے درمیان تعلق کا احاطہ نہیں کریں گے ClassLoader، کیونکہ یہ اس مضمون کا موضوع نہیں ہے۔ اگلا، اس کلاس کے فیلڈز کو بازیافت کرنے کے لیے، آپ کو getFields()طریقہ کو کال کرنے کی ضرورت ہے۔ یہ طریقہ اس کلاس کے تمام قابل رسائی فیلڈز کو واپس کر دے گا۔ یہ ہمارے لیے کام نہیں کرتا، کیونکہ ہمارا فیلڈ نجی ہے ، اس لیے ہم getDeclaredFields()طریقہ استعمال کرتے ہیں۔ یہ طریقہ کلاس فیلڈز کی ایک صف کو بھی لوٹاتا ہے، لیکن اب اس میں نجی اور محفوظ فیلڈز شامل ہیں۔ اس معاملے میں، ہم اس فیلڈ کا نام جانتے ہیں جس میں ہماری دلچسپی ہے، لہذا ہم طریقہ استعمال کر سکتے ہیں ، مطلوبہ فیلڈ کا نام getDeclaredField(String)کہاں ہے۔Stringنوٹ: getFields()اور getDeclaredFields()والدین کی کلاس کے کھیتوں کو واپس نہ کریں! زبردست. ہمیں اپنے نام کاField حوالہ دیتے ہوئے ایک اعتراض ملا ۔ چونکہ فیلڈ عوامی نہیں تھا ، ہمیں اس کے ساتھ کام کرنے کے لیے رسائی فراہم کرنی چاہیے۔ طریقہ ہمیں آگے بڑھنے دیتا ہے۔ اب نام کا میدان ہمارے مکمل کنٹرول میں ہے! آپ آبجیکٹ کے طریقہ کار کو کال کر کے اس کی قدر حاصل کر سکتے ہیں، جہاں ہماری کلاس کی ایک مثال ہے۔ ہم قسم کو تبدیل کرتے ہیں اور اپنے نام کے متغیر کو قدر تفویض کرتے ہیں ۔ اگر ہمیں نام کی فیلڈ میں نئی ​​قدر متعین کرنے کے لیے کوئی سیٹر نہیں ملتا ہے ، تو آپ سیٹ طریقہ استعمال کر سکتے ہیں: setAccessible(true)Fieldget(Object)ObjectMyClassString
field.set(myClass, (String) "new value");
مبارک ہو! آپ نے صرف عکاسی کی بنیادی باتوں میں مہارت حاصل کی ہے اور ایک نجی فیلڈ تک رسائی حاصل کی ہے! try/catchبلاک اور مستثنیات کی اقسام پر توجہ دیں ۔ IDE آپ کو بتائے گا کہ ان کی موجودگی خود ہی ضروری ہے، لیکن آپ واضح طور پر ان کے ناموں سے بتا سکتے ہیں کہ وہ یہاں کیوں ہیں۔ آگے بڑھ رہے ہیں! جیسا کہ آپ نے دیکھا ہوگا، ہماری MyClassکلاس میں پہلے سے ہی کلاس ڈیٹا کے بارے میں معلومات ظاہر کرنے کا طریقہ موجود ہے:
private void printData(){
       System.out.println(number + name);
   }
لیکن اس پروگرامر نے اپنے فنگر پرنٹس کو یہاں بھی چھوڑ دیا۔ طریقہ کار میں ایک پرائیویٹ رسائی موڈیفائر ہے، اور ہمیں ہر بار ڈیٹا ڈسپلے کرنے کے لیے اپنا کوڈ لکھنا پڑتا ہے۔ کیا گڑبڑ. ہمارا عکس کہاں گیا؟ درج ذیل فنکشن لکھیں:
public static void printData(Object myClass){
   try {
       Method method = myClass.getClass().getDeclaredMethod("printData");
       method.setAccessible(true);
       method.invoke(myClass);
   } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
       e.printStackTrace();
   }
}
یہاں طریقہ کار وہی ہے جو کسی فیلڈ کو بازیافت کرنے کے لیے استعمال کیا جاتا ہے۔ ہم نام کے ذریعہ مطلوبہ طریقہ تک رسائی حاصل کرتے ہیں اور اس تک رسائی فراہم کرتے ہیں۔ اور جس Methodچیز کو ہم invoke(Object, Args)طریقہ کہتے ہیں اس پر کلاس Objectکی ایک مثال بھی ہے MyClass۔ Argsطریقہ کے دلائل ہیں، حالانکہ ہمارے پاس کوئی نہیں ہے۔ اب ہم printDataمعلومات کو ظاہر کرنے کے لیے فنکشن کا استعمال کرتے ہیں:
public static void main(String[] args) {
   MyClass myClass = new MyClass();
   int number = myClass.getNumber();
   String name = null; //?
   printData(myClass); // Output: 0default
   try {
       Field field = myClass.getClass().getDeclaredField("name");
       field.setAccessible(true);
       field.set(myClass, (String) "new value");
       name = (String) field.get(myClass);
   } catch (NoSuchFieldException | IllegalAccessException e) {
       e.printStackTrace();
   }
   printData(myClass);// Output: 0new value
}
ہیرے! اب ہمیں کلاس کے نجی طریقہ تک رسائی حاصل ہے۔ لیکن کیا ہوگا اگر طریقہ کار میں دلائل ہوں، اور کنسٹرکٹر پر تبصرہ کیوں کیا جاتا ہے؟ ہر چیز اپنے مقررہ وقت میں۔ یہ شروع میں تعریف سے واضح ہے کہ عکاسی آپ کو رن ٹائم (جب پروگرام چل رہا ہے) میں کلاس کی مثالیں تخلیق کرنے دیتا ہے ! ہم کلاس کا پورا نام استعمال کر کے ایک آبجیکٹ بنا سکتے ہیں۔ کلاس کا پورا نام کلاس کا نام ہے، بشمول اس کے پیکیج کا راستہ ۔
Reflection API: عکاسی۔  جاوا کا تاریک پہلو - 2
میرے پیکیج کے درجہ بندی میں، MyClass کا پورا نام "reflection.MyClass" ہوگا۔ کلاس کا نام سیکھنے کا ایک آسان طریقہ بھی ہے (کلاس کا نام سٹرنگ کے طور پر واپس کریں):
MyClass.class.getName()
آئیے کلاس کی مثال بنانے کے لیے جاوا ریفلیکشن کا استعمال کریں:
public static void main(String[] args) {
   MyClass myClass = null;
   try {
       Class clazz = Class.forName(MyClass.class.getName());
       myClass = (MyClass) clazz.newInstance();
   } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
       e.printStackTrace();
   }
   System.out.println(myClass); // Output: created object reflection.MyClass@60e53b93
}
جب جاوا ایپلیکیشن شروع ہوتی ہے، تمام کلاسز JVM میں لوڈ نہیں ہوتی ہیں۔ اگر آپ کا کوڈ کلاس کا حوالہ نہیں دیتا ہے MyClass، تو ClassLoader، جو JVM میں کلاسز لوڈ کرنے کا ذمہ دار ہے، کلاس کو کبھی لوڈ نہیں کرے گا۔ اس کا مطلب ہے کہ آپ کو اسے لوڈ کرنے پر مجبور کرنا ہوگا اور متغیر ClassLoaderکی شکل میں کلاس کی تفصیل حاصل کرنی ہوگی ۔ Classیہی وجہ ہے کہ ہمارے پاس forName(String)طریقہ ہے، Stringاس کلاس کا نام کہاں ہے جس کی تفصیل ہمیں درکار ہے۔ آبجیکٹ حاصل کرنے کے بعد Сlass، طریقہ کو کال کرنے سے اس تفصیل کا استعمال کرتے ہوئے تخلیق کردہ آبجیکٹ newInstance()واپس آجائے گا ۔ Objectبس ہماری MyClassکلاس کو اس چیز کی فراہمی باقی ہے۔ ٹھنڈا! یہ مشکل تھا، لیکن قابل فہم، مجھے امید ہے۔ اب ہم لفظی طور پر ایک لائن میں کلاس کی مثال بنا سکتے ہیں! بدقسمتی سے، بیان کردہ نقطہ نظر صرف ڈیفالٹ کنسٹرکٹر (پیرامیٹر کے بغیر) کے ساتھ کام کرے گا۔ آپ پیرامیٹرز کے ساتھ طریقوں اور کنسٹرکٹرز کو کیسے کہتے ہیں؟ یہ ہمارے کنسٹرکٹر کو غیر تبصرہ کرنے کا وقت ہے۔ جیسا کہ توقع کی گئی ہے، newInstance()ڈیفالٹ کنسٹرکٹر نہیں مل سکتا، اور اب کام نہیں کرتا ہے۔ آئیے کلاس انسٹینٹیشن کو دوبارہ لکھتے ہیں:
public static void main(String[] args) {
   MyClass myClass = null;
   try {
       Class clazz = Class.forName(MyClass.class.getName());
       Class[] params = {int.class, String.class};
       myClass = (MyClass) clazz.getConstructor(params).newInstance(1, "default2");
   } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
       e.printStackTrace();
   }
   System.out.println(myClass);// Output: created object reflection.MyClass@60e53b93
}
کلاس کنسٹرکٹرز کو حاصل کرنے کے لیے اس getConstructors()طریقہ کو کلاس ڈیفینیشن پر بلایا جانا چاہیے، اور پھر getParameterTypes()کنسٹرکٹر کے پیرامیٹرز حاصل کرنے کے لیے بلایا جانا چاہیے:
Constructor[] constructors = clazz.getConstructors();
for (Constructor constructor : constructors) {
   Class[] paramTypes = constructor.getParameterTypes();
   for (Class paramType : paramTypes) {
       System.out.print(paramType.getName() + " ");
   }
   System.out.println();
}
اس سے ہمیں تمام کنسٹرکٹرز اور ان کے پیرامیٹرز مل جاتے ہیں۔ میری مثال میں، میں ایک مخصوص کنسٹرکٹر کا حوالہ دیتا ہوں جس میں مخصوص، پہلے سے جانا جاتا پیرامیٹرز ہوں۔ اور اس کنسٹرکٹر کو کال کرنے کے لیے، ہم وہ newInstanceطریقہ استعمال کرتے ہیں، جس سے ہم ان پیرامیٹرز کی قدروں کو پاس کرتے ہیں۔ invokeکال کرنے کے طریقے استعمال کرتے وقت بھی ایسا ہی ہوگا ۔ یہ سوال پیدا کرتا ہے: عکاسی کے ذریعے کنسٹرکٹرز کو کال کرنا کب کام آتا ہے؟ جیسا کہ پہلے ہی شروع میں ذکر کیا جا چکا ہے، جدید جاوا ٹیکنالوجیز جاوا ریفلیکشن API کے بغیر حاصل نہیں ہو سکتیں۔ مثال کے طور پر، Dependency Injection (DI)، جو کہ طریقوں اور کنسٹرکٹرز کی عکاسی کے ساتھ تشریحات کو جوڑ کر اینڈرائیڈ کی ترقی کے لیے مقبول ڈیر لائبریری کی تشکیل کرتا ہے۔ اس مضمون کو پڑھنے کے بعد، آپ اعتماد کے ساتھ اپنے آپ کو Java Reflection API کے طریقوں سے تعلیم یافتہ سمجھ سکتے ہیں۔ وہ عکاسی کو جاوا کا تاریک پہلو نہیں کہتے ہیں۔ یہ مکمل طور پر OOP پیراڈائم کو توڑ دیتا ہے۔ جاوا میں، encapsulation کچھ پروگرام کے اجزاء تک دوسروں کی رسائی کو چھپاتا اور محدود کرتا ہے۔ جب ہم پرائیویٹ موڈیفائر کا استعمال کرتے ہیں، تو ہمارا ارادہ ہے کہ اس فیلڈ تک رسائی صرف اس کلاس کے اندر سے کی جائے جہاں یہ موجود ہے۔ اور ہم اس اصول کی بنیاد پر پروگرام کے بعد کے فن تعمیر کو بناتے ہیں۔ اس مضمون میں، ہم نے دیکھا ہے کہ آپ کسی بھی جگہ پر مجبور ہونے کے لیے عکاسی کا استعمال کیسے کر سکتے ہیں۔ تخلیقی ڈیزائن پیٹرن سنگلٹن ایک آرکیٹیکچرل حل کے طور پر اس کی ایک اچھی مثال ہے۔ بنیادی خیال یہ ہے کہ اس طرز کو نافذ کرنے والی کلاس کے پاس پورے پروگرام کے عمل کے دوران صرف ایک مثال ہوگی۔ یہ ڈیفالٹ کنسٹرکٹر میں پرائیویٹ رسائی موڈیفائر کو شامل کرکے پورا کیا جاتا ہے۔ اور یہ بہت برا ہوگا اگر کوئی پروگرامر اس طرح کی کلاسوں کی مزید مثالیں تخلیق کرنے کی عکاسی کا استعمال کرے۔ ویسے، میں نے حال ہی میں ایک ساتھی کارکن کو ایک بہت ہی دلچسپ سوال کرتے ہوئے سنا: کیا سنگلٹن پیٹرن کو نافذ کرنے والی کلاس کو وراثت میں مل سکتا ہے؟ کیا یہ ہو سکتا ہے کہ اس صورت میں، عکاسی بھی بے اختیار ہو؟ مضمون کے بارے میں اپنی رائے اور نیچے دیئے گئے تبصروں میں اپنا جواب چھوڑیں، اور وہاں اپنے سوالات پوچھیں!

مزید پڑھنا:

تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION