سلام، نوجوان پاداوان. هن آرٽيڪل ۾ آئون توهان کي ان فورس بابت ٻڌايان ٿو، جنهن جي طاقت جاوا پروگرامر صرف هڪ بظاهر نا اميد صورتحال ۾ استعمال ڪندا آهن. تنهن ڪري، جاوا جي اونداهي طرف آهي -
Java Reflection API استعمال ڪندي جاوا ۾ عڪس ڪيو ويندو آهي. هي عڪس ڇا آهي؟ هڪ مختصر ۽ صحيح وصف آهي جيڪا انٽرنيٽ تي پڻ مشهور آهي. Reflection (مرحوم لاطيني reflexio کان - واپس وڃڻ) هڪ ميکانيزم آهي جيڪو ان جي عمل دوران پروگرام بابت ڊيٽا جي مطالعي لاءِ. Reflection توهان کي اجازت ڏئي ٿو ته معلومات کي جانچڻ لاءِ فيلڊز، طريقن، ۽ ڪلاس جي تعمير ڪندڙ. عکاسي ميڪانيزم پاڻ توهان کي انهن قسمن کي پروسيس ڪرڻ جي اجازت ڏئي ٿو جيڪي تاليف دوران غائب آهن، پر پروگرام جي عمل دوران ظاهر ٿيندا آهن. عکاسي ۽ رپورٽنگ جي غلطي لاء منطقي طور تي مربوط ماڊل جي موجودگي کي درست متحرڪ ڪوڊ ٺاهڻ ممڪن بڻائي ٿو. ٻين لفظن ۾، سمجھڻ ته ڪيئن عکاسي جاوا ۾ ڪم ڪري ٿي توھان لاءِ ڪيترائي شاندار موقعا کولي ٿو. توهان لفظي طور تي طبقن ۽ انهن جي اجزاء کي ڇڪي سگهو ٿا.
هتي هڪ بنيادي فهرست آهي جنهن جي عڪاسي جي اجازت ڏئي ٿي:
منهنجي درجه بندي ۾،
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);
}
}
جيئن اسان ڏسي سگهون ٿا، اهو سڀ کان وڌيڪ عام طبقو آهي. پيرا ميٽرز سان ٺاھيندڙ ھڪڙي سبب لاءِ تبصرو ڪيو ويو آھي، اسان ان کي بعد ۾ واپس ڪنداسين. جيڪڏهن توهان ڪلاس جي مواد کي ويجهي کان ڏٺو، توهان شايد getter
'a' جي غير موجودگي کي ڏٺو name
. فيلڊ پاڻ name
هڪ رسائي موڊيفائر سان نشان لڳل آهي private
؛ اسان ان کي ڪلاس کان ٻاهر تائين رسائي نٿا ڪري سگهون؛ =>
اسان ان جي قيمت حاصل نٿا ڪري سگهون. ”پوءِ مسئلو ڇا آهي؟ - توهان بڌايو. " getter
رسائي موڊيفائر کي شامل ڪريو يا تبديل ڪريو." ۽ توهان صحيح ٿا چئو، پر ڇا جيڪڏهن MyClass
اهو هڪ مرتب ٿيل آر آر لائبريري ۾ هجي يا ڪنهن ٻئي بند ماڊل ۾ بغير ايڊيٽنگ جي رسائي، ۽ عملي طور تي اهو تمام گهڻو ٿئي ٿو. ۽ ڪجهه بي پرواهه پروگرامر صرف لکڻ وساري ويٺا getter
. اهو عڪس جي باري ۾ ياد ڪرڻ جو وقت آهي! اچو ته ڪوشش ڪريون ڪلاس جي private
ميدان ۾ : name
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()
، هي طريقو اسان کي ڪلاس جا سڀ موجود فيلڊ واپس ڏيندو. اهو اسان لاءِ موزون نه آهي، ڇاڪاڻ ته اسان جي فيلڊ آهي private
، ان ڪري اسان اهو طريقو استعمال ڪريون ٿا getDeclaredFields()
، اهو طريقو پڻ ڪلاس فيلڊز جي هڪ صف کي واپس ڏئي ٿو، پر هاڻي ٻنهي private
۽ protected
. اسان جي صورتحال ۾، اسان ڄاڻون ٿا ته فيلڊ جو نالو جيڪو اسان جي فائدي ۾ آهي، ۽ اسان اهو طريقو استعمال ڪري سگهون ٿا getDeclaredField(String)
، جتي String
گهربل فيلڊ جو نالو آهي. نوٽ: getFields()
۽ getDeclaredFields()
والدين طبقي جا شعبا واپس نه ڏيو! عظيم، اسان کي Field
اسان جي لنڪ سان هڪ اعتراض مليو name
. ڇاڪاڻ ته فيلڊ публичным
(عوامي) نه هئي، ان سان ڪم ڪرڻ لاء رسائي ڏني وڃي. طريقو setAccessible(true)
اسان کي ڪم جاري رکڻ جي اجازت ڏئي ٿو. هاڻي ميدان name
مڪمل طور تي اسان جي قبضي هيٺ آهي! get(Object)
توھان ان جي قيمت حاصل ڪري سگھو ٿا اعتراض کي ڪال ڪندي Field
، جتي Object
اسان جي ڪلاس جو ھڪڙو مثال آھي MyClass
. اسان ان کي اڇلائي ڇڏيو String
۽ ان کي اسان جي متغير کي تفويض ڪيو name
. صورت ۾ اسان کي اوچتو نه آهي setter
'a، اسان طريقي سان استعمال ڪري سگھون ٿا نالي جي فيلڊ لاء نئين قيمت مقرر ڪرڻ لاء set
:
field.set(myClass, (String) "new value");
مبارڪون هجن! توهان صرف فڪر جي بنيادي ميکانيزم ۾ مهارت حاصل ڪئي آهي ۽ private
فيلڊ تائين رسائي حاصل ڪرڻ جي قابل هئا! بلاڪ تي ڌيان ڏيو try/catch
۽ استثناء جي قسمن کي سنڀاليو. IDE پاڻ انهن جي لازمي موجودگي کي ظاهر ڪندو، پر انهن جو نالو اهو واضح ڪري ٿو ته اهي هتي ڇو آهن. اڳتي وڃو! جيئن توهان محسوس ڪيو هوندو، اسان وٽ MyClass
اڳ ۾ ئي ڪلاس ڊيٽا بابت معلومات ڏيکارڻ جو طريقو آهي:
private void printData(){
System.out.println(number + name);
}
پر هن پروگرامر هتي به هڪ وراثت ڇڏي. طريقو رسائي موڊيفائر جي تحت آهي private
، ۽ اسان کي هر وقت پنهنجو پاڻ کي آئوٽ ڪوڊ لکڻو پوندو. اهو ترتيب ۾ ناهي ته اسان جو عڪس ڪٿي آهي؟... اچو ته هيٺيون فنڪشن لکون:
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(Оbject, Args)
، جتي Оbject
پڻ ڪلاس جو هڪ مثال آهي MyClass
. Args
- طريقو دليل - اسان جو ڪو به نه آهي. ھاڻي اسان معلومات کي ڊسپلي ڪرڻ لاء فنڪشن استعمال ڪندا آھيون printData
:
public static void main(String[] args) {
MyClass myClass = new MyClass();
int number = myClass.getNumber();
String name = null; //?
printData(myClass); // outout 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
}
هير، هاڻي اسان کي ڪلاس جي نجي طريقي تائين رسائي آهي. پر ڇا ٿيندو جيڪڏهن طريقو اڃا تائين دليل آهي، ۽ اتي هڪ تبصرو ٿيل تعمير ڪندڙ ڇو آهي؟ هر شيءِ جو پنهنجو وقت آهي. شروعات ۾ تعريف کان اهو واضح آهي ته عڪاسي توهان کي موڊ ۾ ڪلاس جا مثال ٺاهڻ جي اجازت ڏئي ٿي runtime
(جڏهن ته پروگرام هلندي آهي)! اسان ان طبقي جي مڪمل طور تي قابليت واري نالي سان هڪ ڪلاس جو هڪ اعتراض ٺاهي سگهون ٿا. مڪمل طور تي قابل ڪلاس جو نالو ڪلاس جو نالو آھي، جنھن ۾ ان کي رستو ڏنو ويو آھي package
.
package
پورو نالو 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
، ته پوءِ جيڪو به ذميوار آهي ڪلاسز کي JVM ۾ لوڊ ڪرڻ جو، ۽ اهو آهي ClassLoader
، ان کي اتي ڪڏهن به لوڊ نه ڪندو. تنهن ڪري، اسان کي 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 کان سواءِ نٿا ڪري سگهن. مثال طور، DI (Dependency Injection)، جتي تشريحون ملن ٿيون طريقن جي عڪاسي ۽ ڪنسٽرڪٽرز ڊاگر لائبريري ٺاهي ٿي، جيڪا Android ڊولپمينٽ ۾ مشهور آهي. هن مضمون کي پڙهڻ کان پوء، توهان اعتماد سان سمجهي سگهو ٿا پاڻ کي روشن خيال ريفليشن API جي ميڪانيزم ۾. اهو ڪجھ به نه آهي ته عڪاسي کي جاوا جي اونداهي طرف سڏيو ويندو آهي. اهو مڪمل طور تي OOP پيراگراف کي ٽوڙي ٿو. جاوا ۾، encapsulation کي لڪائڻ ۽ محدود ڪرڻ جي خدمت ڪري ٿو ڪجهه پروگرام جي اجزاء جي رسائي ٻين تائين. پرائيويٽ موڊيفائر استعمال ڪرڻ سان اسان جو مطلب آهي ته هن فيلڊ تائين پهچ صرف ان طبقي جي اندر هوندي جتي هي فيلڊ موجود آهي، ان جي بنياد تي اسان پروگرام جو وڌيڪ فن تعمير ڪندا آهيون. هن آرٽيڪل ۾، اسان ڏٺو ته توهان ڪٿي به حاصل ڪرڻ لاء عڪس ڪيئن استعمال ڪري سگهو ٿا. هڪ آرڪيٽيڪچرل حل جي صورت ۾ هڪ سٺو مثال پيدا ٿيندڙ ڊيزائن جو نمونو آهي - Singleton
. ان جو بنيادي خيال اهو آهي ته پروگرام جي پوري آپريشن دوران، هن ٽيمپليٽ کي لاڳو ڪندڙ طبقي وٽ صرف هڪ ڪاپي هجڻ گهرجي. اهو ڪيو ويندو آهي ڊفالٽ رسائي موڊيفائر کي ترتيب ڏيڻ لاءِ پرائيويٽ ۾. ۽ اهو تمام خراب ٿيندو جيڪڏهن ڪو پروگرامر پنهنجي عڪاسي سان اهڙا ڪلاس ٺاهي. رستي ۾، هڪ تمام دلچسپ سوال آهي جيڪو مون تازو پنهنجي ملازم کان ٻڌو آهي: ڇا هڪ طبقو جيڪو ٽيمپليٽ کي لاڳو ڪري ٿو، Singleton
وارث ٿي سگهي ٿو؟ ڇا اهو ممڪن آهي ته هن معاملي ۾ به عڪاسي بي طاقت آهي؟ مضمون تي پنهنجا تاثرات ۽ جواب تبصرن ۾ لکو، ۽ پڻ پنھنجا سوال پڇو! Reflection API جي حقيقي طاقت رن ٽائم اينوٽيشنز سان ميلاپ ۾ اچي ٿي، جيڪا اسان شايد مستقبل جي مضمون ۾ جاوا جي اونداهي پاسي بابت ڳالهائينداسين. توهان جي توجه لاء مهرباني!
GO TO FULL VERSION