سلام اڄ جي سبق ۾، اسين generics جو مطالعو جاري رکنداسين. جيئن ته ائين ٿئي ٿو، اهو هڪ وڏو موضوع آهي، پر ان کان بچڻ جي ڪا به ضرورت ناهي - اها ٻولي جو هڪ انتهائي اهم حصو آهي :) جڏهن توهان Oracle ڊاڪيومينٽيشن کي جنريڪس تي پڙهو ٿا يا آن لائن سبق پڙهو ٿا، توهان کي اصطلاحن تي نظر اينديون غير قابل تصديق قسمون ۽ قابل تجديد قسم . ريفائيبل قسم ھڪڙو قسم آھي جنھن لاء معلومات مڪمل طور تي دستياب آھي رن ٽائم تي. جاوا ۾، اهڙن قسمن ۾ شامل آهن پرائمري، خام قسم، ۽ غير عام قسم. ان جي ابتڙ، غير ريفائيبل قسم جا قسم آهن جن جي معلومات ختم ٿي ويندي آهي ۽ رن ٽائم تي ناقابل رسائي ٿي ويندي آهي. جيئن ته اهو ٿئي ٿو، اهي عام آهن -
List<String>
، List<Integer>
وغيره.
رستي جي ذريعي، توهان کي ياد آهي ته varargs ڇا آهي؟
صورت ۾ توهان وساري ڇڏيو، هي هڪ متغير ڊگھائي دليل آهي. اهي انهن حالتن ۾ ڪارائتو آهن جتي اسان کي خبر ناهي ته اسان جي طريقي سان ڪيترا دليل منظور ڪيا ويندا. مثال طور، جيڪڏهن اسان وٽ هڪ ڳڻپيوڪر طبقو آهي جنهن ۾ هڪsum
طريقو آهي. طريقو sum()
حاصل ڪري سگھي ٿو 2 نمبر، يا 3، يا 5، يا جيترو توھان چاھيو. sum()
اهو هر ممڪن دليلن لاءِ طريقي کي اوور لوڊ ڪرڻ تمام عجيب هوندو . ان جي بدران، اسان اهو ڪري سگهون ٿا:
public class SimpleCalculator {
public static int sum(int...numbers) {
int result = 0;
for(int i : numbers) {
result += i;
}
return result;
}
public static void main(String[] args) {
System.out.println(sum(1,2,3,4,5));
System.out.println(sum(2,9));
}
}
ڪنسول آئوٽ:
15
11
هي اسان کي ڏيکاري ٿو ته ڪي اهم خاصيتون آهن جڏهن varargs استعمال ڪندي جنريڪس سان ميلاپ ۾. اچو ته هيٺ ڏنل ڪوڊ ڏسو:
import javafx.util.Pair;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static <E> void addAll(List<E> list, E... array) {
for (E element : array) {
list.add(element);
}
}
public static void main(String[] args) {
addAll(new ArrayList<String>(), // This is okay
"Leonardo da Vinci",
"Vasco de Gama"
);
// but here we get a warning
addAll(new ArrayList<Pair<String, String>>(),
new Pair<String, String>("Leonardo", "da Vinci"),
new Pair<String, String>("Vasco", "de Gama")
);
}
}
طريقو addAll()
انپٽ جي طور تي وٺندو آهي a List<E>
۽ ڪنهن به شئي جو تعداد E
، ۽ پوء اهو انهن سڀني شين کي لسٽ ۾ شامل ڪري ٿو. طريقي ۾ main()
، اسان کي اسان جو addAll()
طريقو ٻه ڀيرا سڏين ٿا. پهرين صورت ۾، اسان ٻه عام اسٽرنگ شامل ڪندا آهيون List
. هتي هر شي ترتيب ۾ آهي. ٻئي صورت ۾، اسان ٻه Pair<String, String>
شيون شامل ڪيون ٿا List
. پر هتي اسان کي غير متوقع طور تي هڪ ڊيڄاريندڙ ملي ٿي:
Unchecked generics array creation for varargs parameter
هن جو مطلب ڇا آهي؟ اسان کي هڪ ڊيڄاريندڙ ڇو حاصل ڪيو وڃي ۽ ڇو ڪو ذڪر آهي array
؟ سڀ کان پوء، اسان جو ڪوڊ نه آهي array
! اچو ته ٻئي ڪيس سان شروع ڪريون. ڊيڄاريندڙ هڪ صف جو ذڪر ڪري ٿو ڇاڪاڻ ته مرتب ڪندڙ متغير-لمبائي دليل (varargs) کي هڪ صف ۾ تبديل ڪري ٿو. ٻين لفظن ۾، اسان جي طريقي جي دستخط addAll()
آهي:
public static <E> void addAll(List<E> list, E... array)
اهو اصل ۾ هن وانگر ڏسڻ ۾ اچي ٿو:
public static <E> void addAll(List<E> list, E[] array)
اهو آهي، main()
طريقي ۾، ڪمپلر اسان جي ڪوڊ کي هن ۾ تبديل ڪري ٿو:
public static void main(String[] args) {
addAll(new ArrayList<String>(),
new String[] {
"Leonardo da Vinci",
"Vasco de Gama"
}
);
addAll(new ArrayList<Pair<String,String>>(),
new Pair<String,String>[] {
new Pair<String,String>("Leonardo","da Vinci"),
new Pair<String,String>("Vasco","de Gama")
}
);
}
هڪ String
صف بلڪل ٺيڪ آهي. پر هڪ Pair<String, String>
صف نه آهي. مسئلو اهو آهي ته Pair<String, String>
هڪ غير ريفائيبل قسم آهي. تاليف جي دوران، قسم جي دلائل بابت سڀ معلومات (<String، String>) ختم ٿي ويندي آهي. جاوا ۾ غير ريفائيبل قسم جي صفن کي ٺاهڻ جي اجازت ناهي . توھان ھي ڏسي سگھو ٿا جيڪڏھن توھان ڪوشش ڪريو دستي طور ھڪڙو جوڙو ٺاھيو<String, String> array
public static void main(String[] args) {
// Compilation error Generic array creation
Pair<String, String>[] array = new Pair<String, String>[10];
}
سبب واضح آهي: قسم جي حفاظت. جيئن توهان کي ياد هوندو، جڏهن هڪ صف ٺاهيندي، توهان کي يقيني طور تي وضاحت ڪرڻ جي ضرورت آهي ته ڪهڙيون شيون (يا پرائمري) سرن کي ذخيرو ڪندو.
int array[] = new int[10];
اسان جي پوئين سبقن مان هڪ ۾، اسان تفصيل سان ٽائپ ايريچر جو جائزو ورتو. انهي صورت ۾، ٽائيپ erasure اسان کي ان معلومات کي وڃائڻ جو سبب بڻائيندو آهي جيڪي Pair
شيون جوڙا ذخيرو ڪن ٿيون <String, String>
. صف ٺاهڻ غير محفوظ هوندو. جڏهن طريقن کي استعمال ڪندي جنهن ۾ varargs ۽ generics شامل آهن، ياد رکڻ جي پڪ ڪريو ته قسم ختم ڪرڻ ۽ اهو ڪيئن ڪم ڪري ٿو. جيڪڏهن توهان مڪمل طور تي ان ڪوڊ جي باري ۾ پڪ ڄاڻو ٿا جيڪو توهان لکيو آهي ۽ ڄاڻو ٿا ته اهو ڪنهن به مسئلي جو سبب نه ٿيندو، توهان تشريح استعمال ڪندي varargs سان لاڳاپيل ڊيڄاريندڙن کي بند ڪري سگهو ٿا @SafeVarargs
.
@SafeVarargs
public static <E> void addAll(List<E> list, E... array) {
for (E element : array) {
list.add(element);
}
}
جيڪڏھن توھان ھن تشريح کي پنھنجي طريقي ۾ شامل ڪيو، اھو ڊيڄاريندڙ جيڪو اسان اڳ ۾ ڏٺو ھو، ظاهر نه ٿيندو. هڪ ٻيو مسئلو اهو ٿي سگهي ٿو جڏهن عام طور تي varargs استعمال ڪندي هيپ آلودگي آهي. هيپ آلودگي هيٺين صورتحال ۾ ٿي سگهي ٿي:
import java.util.ArrayList;
import java.util.List;
public class Main {
static List<String> polluteHeap() {
List numbers = new ArrayList<Number>();
numbers.add(1);
List<String> strings = numbers;
strings.add("");
return strings;
}
public static void main(String[] args) {
List<String> stringsWithHeapPollution = polluteHeap();
System.out.println(stringsWithHeapPollution.get(0));
}
}
ڪنسول آئوٽ:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
سادي اصطلاحن ۾، هيپ آلودگي اها آهي جڏهن قسم جون شيون A
ڍير ۾ هجن، پر قسم جون شيون B
اتي ختم ٿي وينديون آهن قسم جي حفاظت سان لاڳاپيل غلطين جي ڪري. اسان جي مثال ۾، ائين ئي ٿئي ٿو. پهرين، اسان خام numbers
متغير ٺاهيو ۽ ArrayList<Number>
ان کي هڪ عام مجموعي ( ) لڳايو. ان کان پوء اسان ان نمبر کي 1
گڏ ڪرڻ ۾ شامل ڪيو.
List<String> strings = numbers;
هن لائن تي، مرتب ڪندڙ اسان کي " اڻ چيڪ ٿيل اسائنمينٽ... " وارننگ جاري ڪري ممڪنن غلطين کان ڊيڄارڻ جي ڪوشش ڪئي، پر اسان ان کي نظرانداز ڪيو. اسان ھڪڙي قسم جي عام متغير سان ختم ڪريون ٿا List<String>
جيڪو ھڪڙي قسم جي عام مجموعي ڏانھن اشارو ڪري ٿو ArrayList<Number>
. واضح طور تي، هي صورتحال مصيبت پيدا ڪري سگهي ٿي! ۽ ائين ئي ٿئي ٿو. اسان جي نئين متغير کي استعمال ڪندي، اسان گڏ ڪرڻ لاء هڪ اسٽرنگ شامل ڪندا آهيون. اسان وٽ ھاڻي آلودگي جو ڍير آھي - اسان ھڪڙو نمبر شامل ڪيو ۽ پوءِ ھڪڙي تار کي پيراميٽرائزڊ ڪليڪشن ۾. مرتب ڪندڙ اسان کي خبردار ڪيو، پر اسان ان جي خبرداري کي نظرانداز ڪيو. نتيجي طور، اسان ClassCastException
صرف حاصل ڪندا آهيون جڏهن پروگرام هلندي آهي. تنهن ڪري هن جو varargs سان ڇا تعلق آهي؟ generics سان varargs استعمال ڪرڻ آساني سان آلودگي کي رسي سگهي ٿو. هتي هڪ سادي مثال آهي:
import java.util.Arrays;
import java.util.List;
public class Main {
static void polluteHeap(List<String>... stringsLists) {
Object[] array = stringsLists;
List<Integer> numbersList = Arrays.asList(66,22,44,12);
array[0] = numbersList;
String str = stringsLists[0].get(0);
}
public static void main(String[] args) {
List<String> cars1 = Arrays.asList("Ford", "Fiat", "Kia");
List<String> cars2 = Arrays.asList("Ferrari", "Bugatti", "Zaporozhets");
polluteHeap(cars1, cars2);
}
}
هتي ڇا ٿي رهيو آهي؟ قسم erasure جي ڪري، اسان جي variable-لمبائي دليل
List<String>...stringsLists
فهرستن جي هڪ صف بڻجي وڃي ٿي، يعني List[]
اڻڄاتل قسم جي شين جي (اهو نه وساريو ته varargs تاليف دوران باقاعده صف ۾ تبديل ٿي وڃي ٿي). انهي جي ڪري، اسان ان کي آساني سان ترتيب ڏئي سگھون ٿا Object[] array
متغير کي طريقي جي پهرين لائن ۾ - اسان جي لسٽن ۾ شيون جو قسم ختم ڪيو ويو آهي! ۽ ھاڻي اسان وٽ ھڪڙو Object[]
متغير آھي، جنھن ۾ اسين ڪجھ به شامل ڪري سگھون ٿا، ڇو ته جاوا ۾ سڀ شيون وارث آھن Object
! پهرين ۾، اسان وٽ صرف اسٽرنگ جي فهرستن جي هڪ صف آهي. پر مهرباني ڪري ٽائپ erasure ۽ اسان جي varargs جي استعمال سان، اسان آساني سان انگن جي هڪ فهرست شامل ڪري سگهون ٿا، جيڪو اسان ڪندا آهيون. نتيجي طور، اسان مختلف قسمن جي شين کي گڏ ڪندي ڍير کي آلوده ڪريون ٿا. نتيجو اڃا تائين ٻيو ٿيندو ClassCastException
جڏهن اسان صف مان هڪ اسٽرنگ پڙهڻ جي ڪوشش ڪندا آهيون. ڪنسول آئوٽ:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
اهڙا اڻڄاتل نتيجا varargs استعمال ڪرڻ سبب ٿي سگهن ٿا، هڪ بظاهر سادو ميکانيزم :) ۽ انهي سان گڏ، اڄ جو سبق ختم ٿئي ٿو. ڪجھ ڪمن کي حل ڪرڻ نه وساريو، ۽ جيڪڏھن توھان وٽ وقت ۽ توانائي آھي، ڪجھ اضافي پڙھڻ جو مطالعو ڪريو. ” اثر جاوا
“ پاڻ نه پڙهي سگهندو! :) ٻئي دفعي تائين!
GO TO FULL VERSION