سلام، نوجوان پڈاون۔ اس مضمون میں، میں آپ کو فورس کے بارے میں بتاؤں گا، ایک ایسی طاقت جسے جاوا پروگرامرز صرف بظاہر ناممکن حالات میں استعمال کرتے ہیں۔ جاوا کا تاریک پہلو Reflection API ہے۔ جاوا میں، جاوا ریفلیکشن API کا استعمال کرتے ہوئے عکاسی کو لاگو کیا جاتا ہے۔
میرے پیکیج کے درجہ بندی میں، MyClass کا پورا نام "reflection.MyClass" ہوگا۔ کلاس کا نام سیکھنے کا ایک آسان طریقہ بھی ہے (کلاس کا نام سٹرنگ کے طور پر واپس کریں):
جاوا ریفلیکشن کیا ہے؟
انٹرنیٹ پر ایک مختصر، درست اور مقبول تعریف ہے۔ ریفلیکشن ( دیر سے لاطینی reflexio - واپس جانے کے لیے ) ایک طریقہ کار ہے جس کے چلنے کے دوران کسی پروگرام کے بارے میں ڈیٹا کو دریافت کیا جاتا ہے۔ عکاسی آپ کو فیلڈز، طریقوں اور کلاس کنسٹرکٹرز کے بارے میں معلومات کو دریافت کرنے دیتی ہے۔ ریفلیکشن آپ کو ان اقسام کے ساتھ کام کرنے دیتا ہے جو کمپائل کے وقت موجود نہیں تھیں، لیکن جو رن ٹائم کے دوران دستیاب ہوئیں۔ خامی کی معلومات جاری کرنے کے لیے عکاسی اور منطقی طور پر مسلسل ماڈل درست ڈائنامک کوڈ بنانا ممکن بناتا ہے۔ دوسرے لفظوں میں، یہ سمجھنا کہ جاوا میں عکاسی کیسے کام کرتی ہے آپ کے لیے بہت سے حیرت انگیز مواقع کھولے گی۔ آپ کلاسوں اور ان کے اجزاء کو لفظی طور پر جگا سکتے ہیں۔ یہاں ایک بنیادی فہرست ہے جو عکاسی کی اجازت دیتا ہے:- کسی چیز کی کلاس سیکھیں/تعین کریں؛
- کلاس کے موڈیفائرز، فیلڈز، طریقے، مستقل، کنسٹرکٹرز اور سپر کلاسز کے بارے میں معلومات حاصل کریں۔
- معلوم کریں کہ کون سے طریقے نافذ شدہ انٹرفیس سے تعلق رکھتے ہیں؛
- ایک ایسی کلاس کی مثال بنائیں جس کی کلاس کا نام رن ٹائم تک نامعلوم ہو؛
- نام سے کسی چیز کے فیلڈز کی قدریں حاصل کریں اور سیٹ کریں۔
- کسی چیز کے طریقہ کو نام سے کال کریں۔
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 لائبریری میں نہ ہو یا کسی اور نجی ماڈیول میں تبدیلیاں کرنے کی صلاحیت نہ ہو۔ عملی طور پر، یہ ہر وقت ہوتا ہے. اور کچھ لاپرواہ پروگرامر صرف ایک گیٹر لکھنا بھول گئے ۔ یہ عکاسی کو یاد کرنے کا بہت وقت ہے! آئیے کلاس کے نجی نام والے فیلڈ میں جانے کی کوشش کریں: MyClass
MyClass
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)
Field
get(Object)
Object
MyClass
String
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
}
ہیرے! اب ہمیں کلاس کے نجی طریقہ تک رسائی حاصل ہے۔ لیکن کیا ہوگا اگر طریقہ کار میں دلائل ہوں، اور کنسٹرکٹر پر تبصرہ کیوں کیا جاتا ہے؟ ہر چیز اپنے مقررہ وقت میں۔ یہ شروع میں تعریف سے واضح ہے کہ عکاسی آپ کو رن ٹائم (جب پروگرام چل رہا ہے) میں کلاس کی مثالیں تخلیق کرنے دیتا ہے ! ہم کلاس کا پورا نام استعمال کر کے ایک آبجیکٹ بنا سکتے ہیں۔ کلاس کا پورا نام کلاس کا نام ہے، بشمول اس کے پیکیج کا راستہ ۔

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 کچھ پروگرام کے اجزاء تک دوسروں کی رسائی کو چھپاتا اور محدود کرتا ہے۔ جب ہم پرائیویٹ موڈیفائر کا استعمال کرتے ہیں، تو ہمارا ارادہ ہے کہ اس فیلڈ تک رسائی صرف اس کلاس کے اندر سے کی جائے جہاں یہ موجود ہے۔ اور ہم اس اصول کی بنیاد پر پروگرام کے بعد کے فن تعمیر کو بناتے ہیں۔ اس مضمون میں، ہم نے دیکھا ہے کہ آپ کسی بھی جگہ پر مجبور ہونے کے لیے عکاسی کا استعمال کیسے کر سکتے ہیں۔ تخلیقی ڈیزائن پیٹرن سنگلٹن ایک آرکیٹیکچرل حل کے طور پر اس کی ایک اچھی مثال ہے۔ بنیادی خیال یہ ہے کہ اس طرز کو نافذ کرنے والی کلاس کے پاس پورے پروگرام کے عمل کے دوران صرف ایک مثال ہوگی۔ یہ ڈیفالٹ کنسٹرکٹر میں پرائیویٹ رسائی موڈیفائر کو شامل کرکے پورا کیا جاتا ہے۔ اور یہ بہت برا ہوگا اگر کوئی پروگرامر اس طرح کی کلاسوں کی مزید مثالیں تخلیق کرنے کی عکاسی کا استعمال کرے۔ ویسے، میں نے حال ہی میں ایک ساتھی کارکن کو ایک بہت ہی دلچسپ سوال کرتے ہوئے سنا: کیا سنگلٹن پیٹرن کو نافذ کرنے والی کلاس کو وراثت میں مل سکتا ہے؟ کیا یہ ہو سکتا ہے کہ اس صورت میں، عکاسی بھی بے اختیار ہو؟ مضمون کے بارے میں اپنی رائے اور نیچے دیئے گئے تبصروں میں اپنا جواب چھوڑیں، اور وہاں اپنے سوالات پوچھیں!
مزید پڑھنا: |
---|
GO TO FULL VERSION