JavaRush /جاوا بلاگ /Random-SD /ختم ڪرڻ جا قسم

ختم ڪرڻ جا قسم

گروپ ۾ شايع ٿيل
سلام! اسان جاري رکون ٿا اسان جي ليڪچرن جو سلسلو عام تي. اڳي ، اسان عام اصطلاحن ۾ اهو معلوم ڪيو ته اهو ڇا آهي ۽ ڇو ان جي ضرورت آهي. اڄ اسان عام جي ڪجهه خاصيتن جي باري ۾ ڳالهائينداسين ۽ انهن سان ڪم ڪرڻ دوران ڪجهه نقصانن تي نظر ڪنداسين. وڃ! گذريل ليڪچرختم ڪرڻ جا قسم - 1 ۾ ، اسان عام قسم ۽ خام قسم جي وچ ۾ فرق بابت ڳالهايو . جيڪڏھن توھان وساريو، Raw Type ھڪڙو عام ڪلاس آھي جنھن مان ان جو قسم ختم ڪيو ويو آھي.
List list = new ArrayList();
هتي هڪ مثال آهي. هتي اسان اها وضاحت نه ٿا ڪريون ته ڪهڙي قسم جون شيون اسان جي List. جيڪڏهن اسان هڪ ٺاهڻ جي ڪوشش ڪئي List۽ ان ۾ ڪجهه شيون شامل ڪيون، اسان IDEa ۾ هڪ ڊيڄاريندڙ ڏسندا سين:

“Unchecked call to add(E) as a member of raw type of java.util.List”.
پر اسان ان حقيقت جي باري ۾ به ڳالهايو ته جنريڪس ٻولي جي صرف جاوا 5 ورزن ۾ ئي نظر اچن ٿا. ان جي جاري ٿيڻ وقت پروگرامر ڪافي ڪوڊ لکي چڪا هئا Raw Types استعمال ڪندي، ۽ انهي ڪري ته اهو ڪم ڪرڻ بند نه ڪري. Java ۾ Raw Types سان ٺاھيو ۽ ڪم محفوظ ڪيو ويو. بهرحال، اهو مسئلو تمام گهڻو وسيع ٿي ويو. جاوا ڪوڊ، جيئن توھان ڄاڻو ٿا، خاص بائيٽ ڪوڊ ۾ تبديل ڪيو ويو آھي، جيڪو پوءِ جاوا ورچوئل مشين ذريعي ڪيو ويندو آھي. ۽ جيڪڏهن ترجمي جي عمل دوران اسان پيراميٽر جي قسمن بابت معلومات بائيٽ ڪوڊ ۾ رکون ٿا، ته اهو سڀ اڳي لکيل ڪوڊ ٽوڙي ڇڏيندو، ڇاڪاڻ ته جاوا 5 کان اڳ ڪو به پيٽرول جو قسم موجود نه هو! جڏهن generics سان ڪم ڪرڻ، اتي هڪ تمام اهم خصوصيت آهي ته توهان کي ياد ڪرڻ جي ضرورت آهي. ان کي ٽائپ ايريزر چئبو آهي. ان جو جوهر ان حقيقت ۾ آهي ته ان جي پيٽرول جي قسم بابت ڪا به ڄاڻ ڪلاس اندر محفوظ نه آهي. اها معلومات صرف تاليف واري مرحلي تي موجود آهي ۽ ختم ٿي ويندي آهي (ناقابل رسائي) رن ٽائم تي. جيڪڏهن توهان غلط قسم جي ڪنهن شئي کي پنهنجي ۾ رکڻ جي ڪوشش ڪندا List<String>، مرتب ڪندڙ هڪ غلطي اڇلائي ڇڏيندو. اهو ئي آهي جيڪو ٻوليءَ جي تخليقڪارن حاصل ڪيو آهي جنريڪس ٺاهي - تاليف جي مرحلي ۾ چيڪ. پر جڏهن سڀ جاوا ڪوڊ جيڪي توهان لکندا آهيو بائيٽ ڪوڊ ۾ بدلجي ويندا آهن، اتي پيراميٽر جي قسمن بابت ڪا به ڄاڻ نه هوندي. بائيٽ ڪوڊ جي اندر، توهان جي ٻلين جي فهرست تارن List<Cat>کان مختلف نه هوندي . List<String>بائيٽ ڪوڊ ۾ ڪجھ به نه چوندا ته catsهي شيون جي فهرست آهي Cat. انهي جي باري ۾ معلومات گڏ ڪرڻ دوران ختم ٿي ويندي، ۽ صرف اها معلومات جيڪا توهان جي پروگرام ۾ هڪ خاص فهرست آهي بائيٽ ڪوڊ ۾ داخل ٿيندي List<Object> cats. اچو ته ڏسو ته اهو ڪيئن ڪم ڪري ٿو:
public class TestClass<T> {

   private T value1;
   private T value2;

   public void printValues() {
       System.out.println(value1);
       System.out.println(value2);
   }

   public static <T> TestClass<T> createAndAdd2Values(Object o1, Object o2) {
       TestClass<T> result = new TestClass<>();
       result.value1 = (T) o1;
       result.value2 = (T) o2;
       return result;
   }

   public static void main(String[] args) {
       Double d = 22.111;
       String s = "Test String";
       TestClass<Integer> test = createAndAdd2Values(d, s);
       test.printValues();
   }
}
اسان پنهنجو عام ڪلاس ٺاهيو TestClass. اهو بلڪل سادو آهي: بنيادي طور تي اهو 2 شين جو هڪ ننڍڙو "مجموعو" آهي، جيڪو اتي فوري طور تي رکيل آهي جڏهن اعتراض ٺاهيو ويندو آهي. ھن ۾ 2 شيون آھن فيلڊن جي طور تي T. جڏهن طريقي تي عمل ڪيو ويندو آهي، createAndAdd2Values()ٻه پاس ٿيل شيون اسان جي قسم Object aتي اڇلائي وينديون آهن ، جنهن کان پوء اهي اعتراض ۾ شامل ڪيا ويندا . جنهن طريقي سان اسان ٺاهيندا آهيون ، اهو آهي، معيار ۾ اسان وٽ هوندو . پر ساڳئي وقت، اسان طريقي سان هڪ نمبر ۽ اعتراض پاس ڪريون ٿا . ڇا توهان سوچيو ته اسان جو پروگرام ڪم ڪندو؟ آخرڪار، اسان هڪ پيٽرولر جي قسم جي طور تي بيان ڪيو آهي ، پر اهو يقيني طور تي نه ٿو ڪري سگهجي ! اچو ته طريقي سان هلون ۽ چيڪ ڪريو. ڪنسول آئوٽ: 22.111 ٽيسٽ اسٽرنگ اڻڄاتل نتيجو! ائين ڇو ٿيو؟ خاص طور تي قسم ختم ڪرڻ جي ڪري. ڪوڊ گڏ ڪرڻ دوران، اسان جي اعتراض جي پيٽرولر جي قسم بابت معلومات ختم ٿي وئي. هو ۾ بدلجي ويو . اسان جا پيرا ميٽر بغير ڪنهن مسئلي ۾ تبديل ڪيا ويا ( ۽ نه ، جيئن اسان توقع ڪئي!) ۽ خاموشيءَ سان شامل ڪيا ويا . هتي هڪ ٻيو سادو آهي پر تمام نمايان مثال ٽائپ erasure جو: Object bTTestClassmain()TestClass<Integer>TIntegercreateAndAdd2Values()DoubleStringIntegerStringIntegermain()IntegerTestClass<Integer> testTestClass<Object> testDoubleStringObjectIntegerTestClass
import java.util.ArrayList;
import java.util.List;

public class Main {

   private class Cat {

   }

   public static void main(String[] args) {

       List<String> strings = new ArrayList<>();
       List<Integer> numbers = new ArrayList<>();
       List<Cat> cats = new ArrayList<>();

       System.out.println(strings.getClass() == numbers.getClass());
       System.out.println(numbers.getClass() == cats.getClass());

   }
}
ڪنسول آئوٽ پُٽ: صحيح صحيح اهو لڳي ٿو ته اسان ٽن مختلف پيٽرولر جي قسمن سان گڏ مجموعا ٺاهيا آهن - String, Integer, ۽ ڪلاس اسان ٺاهيو Cat. پر بائيٽ ڪوڊ ۾ تبديل ٿيڻ دوران، سڀئي ٽي فهرستون تبديل ٿي ويون List<Object>، پوء جڏهن عمل ڪيو ويو، پروگرام اسان کي ٻڌائي ٿو ته ٽنهي صورتن ۾ اسان ساڳئي طبقي استعمال ڪري رهيا آهيون.

erasure ٽائپ ڪريو جڏهن arrays ۽ generics سان ڪم ڪري رهيا آهيو

هتي هڪ تمام اهم نقطو آهي جيڪو واضح طور تي سمجھڻ گهرجي جڏهن صفن ۽ جنريڪس سان ڪم ڪري رهيو آهي (مثال طور، List). اهو پڻ غور ڪرڻ جي قابل آهي جڏهن توهان جي پروگرام لاء ڊيٽا جي جوڙجڪ کي چونڊيو. Generics قسم جي erasure جي تابع آهن. پيراميٽر جي قسم بابت معلومات پروگرام جي عمل دوران دستياب ناهي. ان جي ابتڙ، arrays ڄاڻن ٿا ۽ پروگرام جي عمل دوران انهن جي ڊيٽا جي قسم بابت معلومات استعمال ڪري سگھن ٿا. غلط قسم جي قيمت کي صف ۾ رکڻ جي ڪوشش ڪندي ھڪڙو استثنا اڇلائي ڇڏيندو:
public class Main2 {

   public static void main(String[] args) {

       Object x[] = new String[3];
       x[0] = new Integer(222);
   }
}
ڪنسول آئوٽ:

Exception in thread "main" java.lang.ArrayStoreException: java.lang.Integer
ڇو ته اتي آھي ھڪڙو وڏو فرق آھي arrays ۽ generics جي وچ ۾، انھن ۾ مطابقت جا مسئلا ٿي سگھن ٿا. سڀ کان پهريان، توهان عام شين جي هڪ صف ٺاهي نه ٿا سگهو يا صرف هڪ ٽائپ ڪيل صف. ٿورڙو مونجهارو لڳي ٿو؟ اچو ته هڪ ويجهي نظر وٺو. مثال طور، توھان جاوا ۾ ھن مان ڪجھ به نٿا ڪري سگھو:
new List<T>[]
new List<String>[]
new T[]
جيڪڏهن اسان فهرستن جي هڪ صف ٺاهڻ جي ڪوشش ڪندا آهيون List<String>، اسان کي هڪ عام صف ٺاهڻ جي تاليف جي غلطي ملي ٿي:
import java.util.List;

public class Main2 {

   public static void main(String[] args) {

       //ошибка компиляции! Generic array creation
       List<String>[] stringLists = new List<String>[1];
   }
}
پر ائين ڇو ڪيو ويو؟ اهڙين صفن جي تخليق ڇو منع ڪئي وئي آهي؟ هي سڀ قسم جي حفاظت کي يقيني بڻائڻ لاء آهي. جيڪڏهن گڏ ڪرڻ وارو اسان کي اجازت ڏئي ٿو ته عام شين مان اهڙيون صفون ٺاهي، اسان تمام گهڻي مصيبت ۾ پئجي سگهون ٿا. هتي جوشوا بلوچ جي ڪتاب ”اثر جاوا“ مان هڪ سادي مثال آهي:
public static void main(String[] args) {

   List<String>[] stringLists = new List<String>[1];  //  (1)
   List<Integer> intList = Arrays.asList(42, 65, 44);  //  (2)
   Object[] objects = stringLists;  //  (3)
   objects[0] = intList;  //  (4)
   String s = stringLists[0].get(0);  //  (5)
}
اچو ته تصور ڪريو ته صف جي تخليق جي List<String>[] stringListsاجازت ڏني ويندي، ۽ مرتب ڪندڙ شڪايت نه ڪندو. هتي اهو آهي ته اسان هن معاملي ۾ ڇا ڪري سگهون ٿا: لائن 1 ۾، اسان شيٽ جي هڪ صف ٺاهيندا آهيون List<String>[] stringLists. اسان جي صف ۾ هڪ شامل آهي List<String>. لائن 2 تي اسان انگن جي هڪ فهرست ٺاهيندا آهيون List<Integer>. لڪير 3 تي اسان پنهنجي صف کي List<String>[]متغير ڏانهن تفويض ڪندا آهيون Object[] objects. جاوا جي ٻولي توھان کي ھي ڪرڻ جي اجازت ڏئي ٿي: Xتوھان ٻئي شيون X۽ شيون سڀني ٻارن جي طبقن جي شين جي ھڪڙي صف ۾ رکي سگھو ٿا Х. انهي جي مطابق، Objectsتوهان صف ۾ ڪجهه به وجهي سگهو ٿا. لائن 4 تي اسين صف جي ھڪڙي عنصر کي objects (List<String>)ھڪڙي فهرست سان تبديل ڪريون ٿا List<Integer>. نتيجي طور، اسان List<Integer>اسان جي صف ۾ رکيا، جنهن جو مقصد صرف ذخيرو ڪرڻ لاء هو List<String>! اسان کي صرف هڪ غلطي نظر ايندي جڏهن ڪوڊ لائن 5 تي پهچندو. هڪ استثنا پروگرام جي عمل دوران اڇلايو ويندو ClassCastException. تنهن ڪري، اهڙي arrays ٺاهڻ تي پابندي جاوا ٻولي ۾ متعارف ڪرايو ويو - هي اسان کي اهڙين حالتن کان بچڻ جي اجازت ڏئي ٿو.

مان ٽائپ ايريچر کي ڪيئن بائي پاس ڪري سگهان ٿو؟

خير، اسان ٽائيپ erasure بابت ڄاڻايو آهي. اچو ته سسٽم کي دوکو ڏيڻ جي ڪوشش ڪريون! :) ٽاسڪ: اسان وٽ ھڪڙو عام طبقو آھي TestClass<T>. اسان کي ان ۾ هڪ طريقو ٺاهڻ جي ضرورت آهي createNewT()جيڪا ٺاهي ۽ واپس آڻيندي نئين قسم جو اعتراض Т. پر اهو ڪرڻ ناممڪن آهي، صحيح؟ قسم جي باري ۾ سڀ معلومات Тگڏ ڪرڻ دوران ختم ٿي ويندي، ۽ جڏهن پروگرام هلندي آهي، اسان اهو نه ڳولي سگهنداسين ته ڪهڙي قسم جي اعتراض کي ٺاهڻ جي ضرورت آهي. حقيقت ۾، اتي ھڪڙو مشڪل طريقو آھي. توھان کي شايد ياد آھي ته جاوا ۾ ھڪڙو ڪلاس آھي Class. ان کي استعمال ڪندي، اسان حاصل ڪري سگھون ٿا اسان جي ڪنهن به شئي جو طبقو:
public class Main2 {

   public static void main(String[] args) {

       Class classInt = Integer.class;
       Class classString = String.class;

       System.out.println(classInt);
       System.out.println(classString);
   }
}
ڪنسول آئوٽ:

class java.lang.Integer
class java.lang.String
پر هتي هڪ خاصيت آهي جنهن بابت اسان ڳالهايو نه آهي. Oracle دستاويزن ۾ توهان ڏسندا ته ڪلاس هڪ عام ڪلاس آهي! ختم ڪرڻ جا قسم - 3دستاويز چوي ٿو: "T ڪلاس جو قسم آهي جيڪو هن ڪلاس اعتراض پاران ماڊل ڪيو ويو آهي." جيڪڏهن اسان هن کي دستاويزي ٻوليءَ مان انساني ٻوليءَ ۾ ترجمو ڪريون ٿا، ته ان جو مطلب آهي ته ڪنهن شئي لاءِ ڪلاس Integer.classصرف نه Class، پر Class<Integer>. اعتراض جو قسم string.classصرف نه آهي Class، Class<String>وغيره. جيڪڏهن اهو اڃا تائين واضح ناهي، پوئين مثال ۾ هڪ قسم جي پيٽرولر شامل ڪرڻ جي ڪوشش ڪريو:
public class Main2 {

   public static void main(String[] args) {

       Class<Integer> classInt = Integer.class;
       //ошибка компиляции!
       Class<String> classInt2 = Integer.class;


       Class<String> classString = String.class;
       //ошибка компиляции!
       Class<Double> classString2 = String.class;
   }
}
۽ ھاڻي، ھن علم کي استعمال ڪندي، اسان ٽائپ ايريچر کي بائي پاس ڪري سگھون ٿا ۽ اسان جو مسئلو حل ڪري سگھون ٿا! اچو ته پيراميٽر جي قسم بابت معلومات حاصل ڪرڻ جي ڪوشش ڪريون. ان جو ڪردار ڪلاس پاران ادا ڪيو ويندو MySecretClass:
public class MySecretClass {

   public MySecretClass() {

       System.out.println("Объект секретного класса успешно создан!");
   }
}
ھتي آھي ڪيئن اسان پنھنجي حل کي عملي طور استعمال ڪريون ٿا:
public class TestClass<T> {

   Class<T> typeParameterClass;

   public TestClass(Class<T> typeParameterClass) {
       this.typeParameterClass = typeParameterClass;
   }

   public T createNewT() throws IllegalAccessException, InstantiationException {
       T t = typeParameterClass.newInstance();
       return t;
   }

   public static void main(String[] args) throws InstantiationException, IllegalAccessException {

       TestClass<MySecretClass> testString = new TestClass<>(MySecretClass.class);
       MySecretClass secret = testString.createNewT();

   }
}
ڪنسول آئوٽ:

Объект секретного класса успешно создан!
اسان صرف اسان جي عام طبقي جي تعمير ڪندڙ کي گهربل ڪلاس پيٽرولر منظور ڪيو:
TestClass<MySecretClass> testString = new TestClass<>(MySecretClass.class);
انهي جي مهرباني، اسان پيراميٽر جي قسم بابت معلومات محفوظ ڪئي ۽ ان کي ختم ٿيڻ کان بچايو. نتيجي طور، اسان هڪ اعتراض پيدا ڪرڻ جي قابل هئا T! :) هي اڄ جي ليڪچر کي ختم ڪري ٿو. ٽائپ ايريچر هميشه ذهن ۾ رکڻ لاءِ ڪجهه هوندو آهي جڏهن عام سان ڪم ڪندي. اهو تمام سولو نه ٿو لڳي، پر توهان کي سمجهڻ جي ضرورت آهي ته جنريڪس جاوا ٻولي جو حصو نه هئا جڏهن اها ٺاهي وئي هئي. هي هڪ بعد ۾ شامل ڪيل خصوصيت آهي جيڪا اسان کي ٽائپ ڪيل مجموعا ٺاهڻ ۽ تاليف جي مرحلي ۾ غلطيون پڪڙڻ ۾ مدد ڪري ٿي. ڪجھ ٻيون ٻوليون جتي generics ورجن 1 کان وٺي لڳن ٿيون انهن ۾ ٽائپ ايريسر نه آهي (مثال طور C#). تنهن هوندي، اسان کي عام اڀياس نه ڪيو ويو آهي! ايندڙ ليڪچر ۾ توهان انهن سان گڏ ڪم ڪرڻ جي ڪيترن ئي وڌيڪ خاصيتن سان واقف ٿي ويندا. ساڳئي وقت ۾، اهو سٺو ٿيندو ته ڪجهه مسئلا حل ڪرڻ لاء! :)
تبصرا
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION