سلام، نوجوان پاداوان. هن آرٽيڪل ۾، مان توهان کي فورس بابت ٻڌايان ٿو، هڪ طاقت جيڪا جاوا پروگرامر صرف بظاهر ناممڪن حالتن ۾ استعمال ڪندا آهن. جاوا جي اونداهي طرف Reflection API آهي. جاوا ۾، عکاسي لاڳو ڪئي وئي آهي Java Reflection API استعمال ڪندي.
منهنجي پيڪيج جي ترتيب ۾، MyClass جو پورو نالو "reflection.MyClass" هوندو. ڪلاس جو نالو سکڻ جو ھڪڙو سادو طريقو پڻ آھي (ڪلاس جو نالو اسٽرنگ طور واپس ڪريو):
جاوا ريفريڪشن ڇا آهي؟
انٽرنيٽ تي هڪ مختصر، صحيح ۽ مشهور تعريف آهي. Reflection ( late لاطيني reflexio - to turn back ) ھڪ ميکانيزم آھي جيڪو ڪنھن پروگرام بابت ڊيٽا کي ڳولڻ لاءِ جڏھن اھو ھلندو ھجي. Reflection توهان کي معلومات ڳولڻ جي اجازت ڏئي ٿي فيلڊز، طريقن، ۽ ڪلاس جي تعمير ڪندڙن بابت. Reflection توهان کي انهن قسمن سان ڪم ڪرڻ جي اجازت ڏئي ٿي جيڪي گڏ ڪرڻ وقت موجود نه هئا، پر جيڪي رن ٽائيم دوران دستياب ٿي ويا. عڪس ۽ منطقي طور تي هڪجهڙائي وارو ماڊل غلط معلومات جاري ڪرڻ لاءِ اهو ممڪن بڻائي ٿو ته صحيح متحرڪ ڪوڊ ٺاهڻ. ٻين لفظن ۾، هڪ سمجھڻ ته ڪيئن عکاسي جاوا ۾ ڪم ڪري ٿي توهان جي لاءِ ڪيترائي شاندار موقعا کوليندا. توهان لفظي طور تي طبقن ۽ انهن جي اجزاء کي ڇڪي سگهو ٿا. هتي هڪ بنيادي فهرست آهي جنهن جي عڪاسي جي اجازت ڏئي ٿي:- سکو / هڪ اعتراض جي درجي جو تعين؛
- ڪلاس جي موڊيفائرز، فيلڊز، طريقن، مستقل، تعمير ڪندڙ، ۽ سپر ڪلاسز بابت ڄاڻ حاصل ڪريو؛
- معلوم ڪريو ته ڪهڙا طريقا لاڳو ٿيل انٽرفيس سان تعلق رکن ٿا؛
- ھڪڙي ڪلاس جو ھڪڙو مثال ٺاھيو جنھن جي ڪلاس جو نالو اڻڄاتل آھي جيستائين هلائڻ وقت؛
- حاصل ڪريو ۽ ھڪڙي شئي جي فيلڊ جا قدر مقرر ڪريو نالي سان؛
- نالي سان هڪ اعتراض جي طريقي کي ڪال ڪريو.
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
ڪال طريقن کي استعمال ڪندي. اهو سوال پيدا ڪري ٿو: جڏهن تعمير ڪندڙن کي موٽڻ جي ذريعي سڏڻ ڪم ۾ اچي ٿو؟ جيئن اڳ ۾ ئي ذڪر ڪيو ويو آهي، جديد جاوا ٽيڪنالاجيون حاصل نه ٿيون ڪري سگهن بغير Java Reflection API. مثال طور، Dependency Injection (DI)، جيڪو طريقن ۽ تعمير ڪندڙن جي عڪاسي سان تشريح کي گڏ ڪري ٿو ته جيئن Android ڊولپمينٽ لاءِ مشهور ڊارر لائبريري ٺاهي. هن آرٽيڪل کي پڙهڻ کان پوء، توهان اعتماد سان سمجهي سگهو ٿا پاڻ کي تعليم يافته جاوا ريفليشن API جي طريقن سان. اهي ريفريڪشن کي جاوا جي اونداهي پاسي نه ٿا سڏين. اهو مڪمل طور تي OOP پيراگراف کي ٽوڙي ٿو. جاوا ۾، encapsulation لڪائيندو آهي ۽ ٻين جي رسائي کي ڪجهه پروگرام جي اجزاء تائين محدود ڪري ٿو. جڏهن اسان پرائيويٽ موڊيفائر استعمال ڪريون ٿا، اسان جو ارادو آهي ته ان فيلڊ کي صرف ان طبقي ۾ پهچايو وڃي جتي اهو موجود آهي. ۽ اسان هن اصول جي بنياد تي پروگرام جي ايندڙ فن تعمير کي ٺاهيو. هن آرٽيڪل ۾، اسان ڏٺو آهي ته توهان ڪيئن استعمال ڪري سگهو ٿا عڪاسي کي پنهنجي رستي تي زور ڏيڻ لاءِ. تخليقي ڊيزائن جو نمونو سنگلٽن هن جو هڪ سٺو مثال آهي آرڪيٽيڪچرل حل جي طور تي. بنيادي خيال اهو آهي ته هڪ طبقو جيڪو هن نموني تي عمل ڪري ٿو، صرف هڪ مثال هوندو سڄي پروگرام جي عمل دوران. اهو مڪمل ڪيو ويو آهي شامل ڪندي پرائيويٽ رسائي موڊيفائر کي ڊفالٽ تعمير ڪندڙ ڏانهن. ۽ اهو تمام خراب ٿيندو جيڪڏهن ڪو پروگرامر عڪاسي استعمال ڪري ته اهڙن ڪلاسن جا وڌيڪ مثال ٺاهي. رستي ۾، مون تازو ٻڌو هڪ همراهه هڪ تمام دلچسپ سوال پڇي ٿو: ڇا هڪ ڪلاس جيڪو سنگلٽن جي نموني کي لاڳو ڪري ٿو وراثت ٿي سگهي ٿو؟ ڇا اهو ٿي سگهي ٿو ته، هن معاملي ۾، عڪاسي به بي طاقت هجي ها؟ ھيٺ ڏنل تبصرن ۾ مضمون ۽ توھان جي جواب بابت پنھنجي راءِ ڏيو، ۽ اتي پنھنجا پنهنجا سوال پڇو!
وڌيڪ پڙهڻ: |
---|
GO TO FULL VERSION