JavaRush /جاوا بلاگ /Random-UR /جاوا جنرکس میں وائلڈ کارڈز

جاوا جنرکس میں وائلڈ کارڈز

گروپ میں شائع ہوا۔
ہیلو! ہم generics کے موضوع کا مطالعہ جاری رکھتے ہیں۔ آپ کو پچھلے لیکچرز سے ان کے بارے میں پہلے سے ہی کافی علم ہے ( جنرکس کے ساتھ کام کرتے وقت اور ٹائپ ایریزر کے بارے میں )، لیکن ہم نے ابھی تک ایک اہم موضوع کا احاطہ نہیں کیا ہے: وائلڈ کارڈز ۔ یہ generics کی ایک بہت اہم خصوصیت ہے۔ اتنا کہ ہم نے اس کے لیے ایک الگ لیکچر مختص کیا ہے! تاہم، وائلڈ کارڈز کے بارے میں کچھ بھی پیچیدہ نہیں ہے، آپ اسے اب دیکھیں گے :) عام میں وائلڈ کارڈز - 1آئیے ایک مثال دیکھتے ہیں:
public class Main {

   public static void main(String[] args) {

       String str = new String("Test!");
       // ниHowих проблем
       Object obj = str;

       List<String> strings = new ArrayList<String>();
       // ошибка компиляции!
       List<Object> objects = strings;
   }
}
یہاں کیا ہو رہا ہے؟ ہم دو بہت ملتے جلتے حالات دیکھتے ہیں۔ ان میں سے پہلے میں، ہم Stringٹائپ کرنے کے لیے ایک چیز ڈالنے کی کوشش کر رہے ہیں Object۔ اس کے ساتھ کوئی مسئلہ نہیں ہے، سب کچھ کام کرتا ہے جیسا کہ یہ ہونا چاہئے. لیکن دوسری صورت حال میں، کمپائلر ایک غلطی پھینک دیتا ہے. اگرچہ ایسا لگتا ہے کہ ہم ایک ہی کام کر رہے ہیں۔ یہ صرف اتنا ہے کہ اب ہم کئی اشیاء کا مجموعہ استعمال کر رہے ہیں۔ لیکن غلطی کیوں ہوتی ہے؟ کیا فرق ہے، بنیادی طور پر، چاہے ہم ایک شے کو Stringایک قسم پر ڈالیں Objectیا 20 اشیاء؟ کسی چیز اور اشیاء کے مجموعے کے درمیان ایک اہم فرق ہے ۔ اگر کوئی طبقہ Bکسی طبقے کا جانشین ہے Аتو Collection<B>وہ جانشین نہیں ہے Collection<A>۔ یہی وجہ ہے کہ ہم اپنے List<String>پاس نہیں لا سکے List<Object>۔ Stringوارث ہے Objectلیکن List<String>وارث نہیں ہے List<Object>۔ بدیہی طور پر، یہ بہت منطقی نظر نہیں آتا۔ زبان کے تخلیق کاروں کو اس اصول کی رہنمائی کیوں کی گئی؟ آئیے تصور کریں کہ مرتب کرنے والا ہمیں یہاں غلطی نہیں دے گا:
List<String> strings = new ArrayList<String>();
List<Object> objects = strings;
اس صورت میں، ہم، مثال کے طور پر، درج ذیل کام کر سکتے ہیں:
objects.add(new Object());
String s = strings.get(0);
چونکہ مرتب کرنے والے نے ہمیں غلطیاں نہیں دی تھیں اور ہمیں List<Object> objectسٹرنگز کے مجموعے کا حوالہ بنانے کی اجازت دی تھی strings، اس لیے ہم stringsسٹرنگ نہیں بلکہ کسی بھی چیز کو شامل کر سکتے ہیں Object! اس طرح، ہم اس بات کی ضمانت کھو چکے ہیں کہ ہمارے مجموعے میں صرف وہی چیزیں ہیں جو عام میں بیان کی گئی ہیںString ۔ یعنی، ہم نے جنرک کا بنیادی فائدہ کھو دیا ہے - قسم کی حفاظت۔ اور چونکہ کمپائلر نے ہمیں یہ سب کرنے کی اجازت دی ہے، اس کا مطلب ہے کہ ہمیں صرف پروگرام کے عمل کے دوران ہی ایک ایرر ملے گا، جو کہ کمپائلیشن ایرر سے کہیں زیادہ بدتر ہے۔ ایسے حالات کو روکنے کے لیے، مرتب کرنے والا ہمیں ایک غلطی دیتا ہے:
// ошибка компиляции
List<Object> objects = strings;
...اور اسے یاد دلاتا ہے کہ List<String>وہ وارث نہیں ہے List<Object>۔ یہ generics کے آپریشن کے لیے ایک لوہے کے کپڑے کا اصول ہے، اور ان کا استعمال کرتے وقت اسے یاد رکھنا چاہیے۔ آئیے آگے بڑھیں۔ ہم کہتے ہیں کہ ہمارے پاس ایک چھوٹا کلاس درجہ بندی ہے:
public class Animal {

   public void feed() {

       System.out.println("Animal.feed()");
   }
}

public class Pet extends Animal {

   public void call() {

       System.out.println("Pet.call()");
   }
}

public class Cat extends Pet {

   public void meow() {

       System.out.println("Cat.meow()");
   }
}
درجہ بندی کے سر پر صرف جانور ہیں: پالتو جانور ان سے وراثت میں ملے ہیں۔ پالتو جانوروں کو 2 اقسام میں تقسیم کیا گیا ہے - کتے اور بلیاں۔ اب تصور کریں کہ ہمیں ایک آسان طریقہ بنانے کی ضرورت ہے iterateAnimals()۔ طریقہ کار کو کسی بھی جانور ( Animal, Pet, Cat, Dog) کے مجموعے کو قبول کرنا چاہیے، تمام عناصر کے ذریعے اعادہ کرنا چاہیے، اور ہر بار کنسول میں کچھ آؤٹ پٹ کرنا چاہیے۔ آئیے اس طریقہ کو لکھنے کی کوشش کرتے ہیں:
public static void iterateAnimals(Collection<Animal> animals) {

   for(Animal animal: animals) {

       System.out.println("Еще один шаг в цикле пройден!");
   }
}
ایسا لگتا ہے کہ مسئلہ حل ہو گیا ہے! تاہم، جیسا کہ ہم نے حال ہی میں پتہ چلا، List<Cat>یا List<Dog>وارث List<Pet>نہیں ہیں List<Animal>! لہذا، جب ہم iterateAnimals()بلیوں کی فہرست کے ساتھ کسی طریقہ کو کال کرنے کی کوشش کرتے ہیں، تو ہمیں ایک کمپائلر ایرر موصول ہوگا:
import java.util.*;

public class Main3 {


   public static void iterateAnimals(Collection<Animal> animals) {

       for(Animal animal: animals) {

           System.out.println("Еще один шаг в цикле пройден!");
       }
   }

   public static void main(String[] args) {


       List<Cat> cats = new ArrayList<>();
       cats.add(new Cat());
       cats.add(new Cat());
       cats.add(new Cat());
       cats.add(new Cat());

       //ошибка компилятора!
       iterateAnimals(cats);
   }
}
ہمارے لیے حالات اچھے نہیں لگ رہے! یہ پتہ چلتا ہے کہ ہمیں ہر قسم کے جانوروں کی گنتی کے لیے الگ الگ طریقے لکھنے ہوں گے؟ دراصل، نہیں، آپ کو یہ کرنے کی ضرورت نہیں ہے :) اور وائلڈ کارڈز اس میں ہماری مدد کریں گے ! ہم مندرجہ ذیل تعمیر کا استعمال کرتے ہوئے، ایک آسان طریقہ کے اندر مسئلہ کو حل کریں گے:
public static void iterateAnimals(Collection<? extends Animal> animals) {

   for(Animal animal: animals) {

       System.out.println("Еще один шаг в цикле пройден!");
   }
}
یہ وائلڈ کارڈ ہے۔ مزید واضح طور پر، یہ وائلڈ کارڈ کی کئی اقسام میں سے پہلا ہے - " extensions " (دوسرا نام Upper Bounded Wildcards ہے )۔ یہ ڈیزائن ہمیں کیا بتاتا ہے؟ Animalاس کا مطلب یہ ہے کہ یہ طریقہ کلاس آبجیکٹ یا کسی بھی نسلی طبقے کی اشیاء کا مجموعہ ان پٹ کے طور پر لیتا ہے Animal (? extends Animal)۔ دوسرے الفاظ میں، طریقہ مجموعہ کو قبول کر سکتا ہے Animal، یا بطور ان پٹ - اس سے کوئی فرق نہیں پڑتا۔ آئیے یقینی بنائیں کہ یہ کام کرتا ہے: PetDogCat
public static void main(String[] args) {

   List<Animal> animals = new ArrayList<>();
   animals.add(new Animal());
   animals.add(new Animal());

   List<Pet> pets = new ArrayList<>();
   pets.add(new Pet());
   pets.add(new Pet());

   List<Cat> cats = new ArrayList<>();
   cats.add(new Cat());
   cats.add(new Cat());

   List<Dog> dogs = new ArrayList<>();
   dogs.add(new Dog());
   dogs.add(new Dog());

   iterateAnimals(animals);
   iterateAnimals(pets);
   iterateAnimals(cats);
   iterateAnimals(dogs);
}
کنسول آؤٹ پٹ:

Еще один шаг в цикле пройден!
Еще один шаг в цикле пройден!
Еще один шаг в цикле пройден!
Еще один шаг в цикле пройден!
Еще один шаг в цикле пройден!
Еще один шаг в цикле пройден!
Еще один шаг в цикле пройден!
Еще один шаг в цикле пройден!
ہم نے کل 4 مجموعے اور 8 آبجیکٹ بنائے ہیں، اور کنسول میں بالکل 8 اندراجات ہیں۔ سب کچھ بہت اچھا کام کرتا ہے! :) وائلڈ کارڈ نے ہمیں ایک طریقہ میں مخصوص اقسام کے پابند ہونے کے ساتھ ضروری منطق کو آسانی سے فٹ کرنے کی اجازت دی۔ ہم نے ہر قسم کے جانور کے لیے الگ طریقہ لکھنے کی ضرورت سے جان چھڑائی۔ تصور کریں کہ اگر ہماری درخواست چڑیا گھر یا ویٹرنری کلینک میں استعمال کی جاتی تو ہمارے پاس کتنے طریقے ہوں گے :) اب آئیے ایک مختلف صورت حال کو دیکھتے ہیں۔ ہمارا وراثت کا درجہ بندی وہی رہے گا: اعلی درجے کی کلاس ہے Animal، بالکل نیچے کلاس پالتو جانور ہے Pet، اور اگلی سطح پر ہے Catاور Dog۔ اب آپ کو طریقہ کو دوبارہ لکھنے کی ضرورت ہے iretateAnimals()تاکہ یہ کتوں کے علاوہ کسی بھی قسم کے جانوروں کے ساتھ کام کر سکے ۔ Collection<Animal>یعنی، اسے قبول کرنا چاہیے ، Collection<Pet>یا بطور ان پٹ Collection<Cat>، لیکن اس کے ساتھ کام نہیں کرنا چاہیے Collection<Dog>۔ ہم یہ کیسے حاصل کر سکتے ہیں؟ ایسا لگتا ہے کہ ہر قسم کے لیے الگ طریقہ لکھنے کا امکان ایک بار پھر ہمارے سامنے آرہا ہے:/ ہم مرتب کرنے والے کو اپنی منطق کی وضاحت کیسے کر سکتے ہیں؟ اور یہ بہت آسانی سے کیا جا سکتا ہے! یہاں وائلڈ کارڈز دوبارہ ہماری مدد کو آئیں گے۔ لیکن اس بار ہم ایک مختلف قسم کا استعمال کریں گے - “ super ” (دوسرا نام Lower Bounded Wildcards ہے )۔
public static void iterateAnimals(Collection<? super Cat> animals) {

   for(int i = 0; i < animals.size(); i++) {

       System.out.println("Еще один шаг в цикле пройден!");
   }
}
اصول یہاں بھی ایسا ہی ہے۔ کنسٹرکشن <? super Cat>کمپائلر کو بتاتی ہے کہ طریقہ iterateAnimals()کلاس Catیا کسی دوسرے آبائی طبقے کی اشیاء کا مجموعہ ان پٹ کے طور پر لے سکتا ہے Cat۔ Catہمارے معاملے میں، کلاس خود ، اس کا آباؤ اجداد - Pets، اور باپ دادا کا باپ - اس وضاحت کے مطابق ہے Animal۔ کلاس Dogاس پابندی میں فٹ نہیں ہے، اور اس وجہ سے فہرست کے ساتھ طریقہ استعمال کرنے کی کوشش کرنے سے List<Dog>تالیف کی غلطی ہو جائے گی:
public static void main(String[] args) {

   List<Animal> animals = new ArrayList<>();
   animals.add(new Animal());
   animals.add(new Animal());

   List<Pet> pets = new ArrayList<>();
   pets.add(new Pet());
   pets.add(new Pet());

   List<Cat> cats = new ArrayList<>();
   cats.add(new Cat());
   cats.add(new Cat());

   List<Dog> dogs = new ArrayList<>();
   dogs.add(new Dog());
   dogs.add(new Dog());

   iterateAnimals(animals);
   iterateAnimals(pets);
   iterateAnimals(cats);

   //ошибка компиляции!
   iterateAnimals(dogs);
}
ہمارا مسئلہ حل ہو گیا، اور دوبارہ وائلڈ کارڈز انتہائی کارآمد ثابت ہوئے :) اس سے لیکچر ختم ہوتا ہے۔ اب آپ دیکھتے ہیں کہ جاوا سیکھتے وقت جنرک کا موضوع کتنا اہم ہے - ہم نے اس پر 4 لیکچرز گزارے! لیکن اب آپ کو موضوع کی اچھی گرفت ہے اور انٹرویو میں اپنے آپ کو ثابت کرنے کے قابل ہو جائیں گے :) اور اب وقت آ گیا ہے کہ کاموں پر واپس جائیں! آپ کی پڑھائی میں اچھی قسمت! :)
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION