تعارف
JSE 5.0 سان شروع ڪندي، جاوا ٻولي جي هٿيارن ۾ عام شامل ڪيا ويا.جاوا ۾ عام ڇا آهن؟
Generics (generalizations) جاوا ٻوليءَ جا خاص وسيلا آھن عام پروگرامنگ کي لاڳو ڪرڻ لاءِ: ڊيٽا ۽ الگورتھم کي بيان ڪرڻ لاءِ ھڪڙو خاص طريقو جيڪو توھان کي اجازت ڏئي ٿو مختلف قسمن جي ڊيٽا سان ڪم ڪرڻ جي بغير انھن جي وضاحت کي تبديل ڪرڻ جي. Oracle ويب سائيٽ تي، هڪ الڳ سبق generics لاء وقف ڪيو ويو آهي: " سبق: عام ".
import java.util.*;
public class HelloWorld{
public static void main(String []args){
List list = new ArrayList();
list.add("Hello");
String text = list.get(0) + ", world!";
System.out.print(text);
}
}
هي ڪوڊ ٺيڪ هلندو. پر ڇا جيڪڏھن اھي اسان وٽ آيا ۽ چوندا ته جملو "هيلو، دنيا!" ماريو ويو ۽ توهان صرف هيلو واپس ڪري سگهو ٿا؟ اچو ته ڪوڊ مان اسٽرنگ سان ڪنٽينشن کي هٽائي ڇڏيو ", world!"
. اهو لڳي ٿو ته ان کان وڌيڪ بي ضرر ڇا ٿي سگهي ٿو؟ پر حقيقت ۾، اسان کي تالیف جي دوران هڪ غلطي ملي ويندي : error: incompatible types: Object cannot be converted to String
شيء اها آهي ته اسان جي صورت ۾ لسٽ قسم جي شين جي فهرست کي محفوظ ڪري ٿو. جيئن ته اسٽرنگ آبجیکٹ جو اولاد آهي (جيئن ته سڀئي طبقن جاوا ۾ آبجیکٹ کان واضح طور تي ورثي ۾ مليا آهن)، ان کي هڪ واضح ڪاسٽ جي ضرورت آهي، جيڪو اسان نه ڪيو آهي. ۽ جڏهن ڳنڍيندي، جامد طريقو String.valueOf(obj) کي سڏيو ويندو اعتراض تي، جيڪو آخرڪار سڏيندو toString طريقو اعتراض تي. اهو آهي، اسان جي لسٽ ۾ اعتراض شامل آهي. اهو ظاهر ٿئي ٿو ته جتي اسان کي هڪ مخصوص قسم جي ضرورت آهي، ۽ اعتراض نه، اسان کي پنهنجو پاڻ کي قسم جي ڪاسٽ ڪرڻ گهرجي:
import java.util.*;
public class HelloWorld{
public static void main(String []args){
List list = new ArrayList();
list.add("Hello!");
list.add(123);
for (Object str : list) {
System.out.println((String)str);
}
}
}
تنهن هوندي به، هن معاملي ۾، ڇاڪاڻ ته لسٽ شين جي هڪ فهرست کي قبول ڪري ٿي، اها نه صرف اسٽرنگ، پر انٽيجر پڻ محفوظ ڪري ٿي. پر بدترين شيء اها آهي ته هن معاملي ۾ مرتب ڪندڙ ڪجهه به غلط نه ڏسندا. ۽ هتي اسان کي EXECUTION دوران هڪ غلطي ملي ويندي (اهي پڻ چوندا آهن ته غلطي "رن ٽائم" تي ملي هئي). غلطي ٿيندي: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
متفق، سڀ کان وڌيڪ خوشگوار نه. ۽ اهو سڀ ڪجهه ان ڪري آهي جو مرتب ڪندڙ مصنوعي ذهانت نه آهي ۽ اهو هر شي جو اندازو نٿو لڳائي سگهي ته پروگرامر جو مطلب آهي. مرتب ڪندڙ کي وڌيڪ ٻڌائڻ لاءِ ته اسان ڪهڙي قسم جا استعمال ڪرڻ وارا آهيون، جاوا SE 5 متعارف ڪرايو generics . اچو ته اسان جي نسخي کي درست ڪريون ته مرتب ڪندڙ کي ٻڌايو ته اسان ڇا چاهيون ٿا:
import java.util.*;
public class HelloWorld {
public static void main(String []args){
List<String> list = new ArrayList<>();
list.add("Hello!");
list.add(123);
for (Object str : list) {
System.out.println(str);
}
}
}
جيئن اسان ڏسي سگهون ٿا، اسان کي هاڻي ڪاسٽ جي ضرورت ناهي String ڏانهن. ان کان علاوه، اسان وٽ هاڻي زاويه بریکٹس آهن جيڪي فريم جنريڪس. ھاڻي مرتب ڪندڙ ڪلاس کي گڏ ڪرڻ جي اجازت نه ڏيندو جيستائين اسان لسٽ ۾ 123 جو اضافو ختم نه ڪندا، ڇاڪاڻ ته هي آهي Integer. اھو اسان کي ٻڌائيندو. ڪيترائي ماڻھو جنريڪس کي سڏيندا آھن "نحوي شگر". ۽ اهي صحيح آهن، ڇو ته عام طور تي اهي ساڳيون ذاتيون بڻجي وينديون آهن جڏهن مرتب ڪيو ويندو. اچو ته مرتب ڪيل طبقن جي بائيٽ ڪوڊ کي ڏسو: دستي ڪاسٽنگ ۽ عام استعمال سان:
خام قسم يا خام قسم
جڏهن عام جي باري ۾ ڳالهائيندي، اسان وٽ هميشه ٻه قسمون آهن: ٽائپ ٿيل قسم (عام قسم) ۽ "خام" قسمون (خام قسم). خام قسم جا قسم آهن بغير بيان ڪرڻ جي "قابليت" جي زاوي بریکٹ ۾:<>
" جي تصور سان جڙيل آھي ، يا قسم جو اندازو. سڀ کان پوء، مرتب ڪندڙ، ڏسندي <> ساڄي پاسي، کاٻي پاسي ڏسڻ ۾ اچي ٿو، جتي متغير جي قسم جو اعلان جنهن جي قيمت مقرر ڪئي وئي آهي، واقع آهي. ۽ هن حصي مان هو سمجهي ٿو ته ساڄي پاسي ڪهڙي قسم جو قدر ٽائيپ ڪيو ويو آهي. حقيقت ۾، جيڪڏهن هڪ عام کاٻي پاسي تي بيان ڪيو ويو آهي ۽ ساڄي پاسي تي بيان نه ڪيو ويو آهي، مرتب ڪندڙ قسم جو اندازو لڳائي سگهندو:
import java.util.*;
public class HelloWorld{
public static void main(String []args) {
List<String> list = new ArrayList();
list.add("Hello World");
String data = list.get(0);
System.out.println(data);
}
}
بهرحال، هي هڪ نئين انداز جو هڪ مرکب هوندو جنريڪس ۽ پراڻي انداز سان انهن کان سواء. ۽ اهو انتهائي ناپسنديده آهي. مٿي ڏنل ڪوڊ گڏ ڪرڻ وقت اسان کي پيغام ملندو: Note: HelloWorld.java uses unchecked or unsafe operations
. حقيقت ۾، اهو واضح ناهي ته هتي هيرن کي شامل ڪرڻ جي ضرورت ڇو آهي. پر هتي هڪ مثال آهي:
import java.util.*;
public class HelloWorld{
public static void main(String []args) {
List<String> list = Arrays.asList("Hello", "World");
List<Integer> data = new ArrayList(list);
Integer intNumber = data.get(0);
System.out.println(data);
}
}
جيئن اسان کي ياد آهي، ArrayList وٽ هڪ ٻيو تعمير ڪندڙ پڻ آهي جيڪو ان پٽ جي طور تي گڏ ڪري ٿو. ۽ هي آهي جتي فريب ڪوڙ آهي. هيرن جي نحو کان سواء، مرتب ڪندڙ اهو نه سمجهي ته اهو ٺڳيو پيو وڃي، پر هيرن سان اهو ڪري ٿو. تنهن ڪري، قاعدو # 1 : هميشه هيرن جي نحو کي استعمال ڪريو جيڪڏهن اسان ٽائپ ڪيل قسم استعمال ڪندا آهيون. ٻي صورت ۾، اسان کي گم ٿيڻ جو خطرو آهي جتي اسان خام قسم استعمال ڪندا آهيون. لاگ ۾ ڊيڄاريندڙن کان بچڻ لاءِ جيڪي ”غير چيڪ ٿيل يا غير محفوظ آپريشنز استعمال ڪن ٿا“ توھان بيان ڪري سگھو ٿا ھڪ خاص تشريح تي جيڪو طريقو يا ڪلاس استعمال ڪيو پيو وڃي: @SuppressWarnings("unchecked")
Suppress جو ترجمو ڪيو ويو آھي دٻائڻ، يعني لفظي طور تي، خبردارين کي دٻائڻ لاءِ. پر سوچيو ته توهان ان جي نشاندهي ڪرڻ جو فيصلو ڇو ڪيو؟ قاعدو نمبر هڪ ياد رکو ۽ شايد توهان کي ٽائپنگ شامل ڪرڻ جي ضرورت آهي.
عام طريقا
Generics توهان کي طريقن کي ٽائپ ڪرڻ جي اجازت ڏئي ٿو. Oracle ٽيوٽوريل ۾ ھن خصوصيت لاءِ وقف ٿيل ھڪڙو الڳ سيڪشن آھي: ” عام طريقا “. هن سبق مان، اهو ضروري آهي ته نحو کي ياد رکڻ لاء:- زاويه بریکٹ جي اندر ٽائپ ڪيل پيٽرولر جي هڪ فهرست شامل آهي؛
- ٽائيپ ٿيل پيٽرولر جي فهرست واپسي واري طريقي کان اڳ وڃي ٿي.
import java.util.*;
public class HelloWorld{
public static class Util {
public static <T> T getValue(Object obj, Class<T> clazz) {
return (T) obj;
}
public static <T> T getValue(Object obj) {
return (T) obj;
}
}
public static void main(String []args) {
List list = Arrays.asList("Author", "Book");
for (Object element : list) {
String data = Util.getValue(element, String.class);
System.out.println(data);
System.out.println(Util.<String>getValue(element));
}
}
}
جيڪڏهن توهان يوٽيل ڪلاس تي نظر وجهو ته ان ۾ اسان کي ٻه ٽائپ ٿيل طريقا نظر اچن ٿا. ٽائيپ انفرنس سان، اسان ٽائيپ جي وصف سڌو سنئون مرتب ڪندڙ کي مهيا ڪري سگھون ٿا، يا اسان ان کي پاڻ بيان ڪري سگھون ٿا. ٻئي اختيار مثال ۾ پيش ڪيا ويا آهن. رستي جي ذريعي، نحو ڪافي منطقي آهي جيڪڏهن توهان ان بابت سوچيو. جڏهن هڪ طريقو ٽائيپ ڪريون ٿا، اسان طريقي کان اڳ عام بيان ڪريون ٿا ڇو ته جيڪڏهن اسان طريقي کان پوء عام استعمال ڪندا آهيون، جاوا اهو معلوم ڪرڻ جي قابل نه هوندو ته ڪهڙي قسم کي استعمال ڪيو وڃي. تنهن ڪري، اسان پهرين اعلان ڪريون ٿا ته اسان عام T استعمال ڪنداسين، ۽ پوء اسان چئون ٿا ته اسان هن عام کي واپس ڪرڻ وارا آهيون. قدرتي طور، Util.<Integer>getValue(element, String.class)
اهو هڪ غلطي سان ناڪام ٿيندو incompatible types: Class<String> cannot be converted to Class<Integer>
. جڏهن ٽائپ ٿيل طريقا استعمال ڪندي، توهان کي هميشه ياد رکڻ گهرجي ٽائپ ايريچر بابت. اچو ته هڪ مثال ڏسو:
import java.util.*;
public class HelloWorld {
public static class Util {
public static <T> T getValue(Object obj) {
return (T) obj;
}
}
public static void main(String []args) {
List list = Arrays.asList(2, 3);
for (Object element : list) {
System.out.println(Util.<Integer>getValue(element) + 1);
}
}
}
اهو وڏو ڪم ڪندو. پر صرف جيستائين ڪمپيلر سمجهي ٿو ته سڏيو ويندو طريقو هڪ Integer قسم آهي. اچو ته ڪنسول آئوٽ پٽ کي ھيٺ ڏنل لائين سان تبديل ڪريون: System.out.println(Util.getValue(element) + 1);
۽ اسان کي غلطي ملي ٿي: بائنري آپريٽر '+' لاءِ خراب operand قسمن، پھريون قسم: Object، ٻيو قسم: int، يعني قسمون ختم ڪيون ويون آھن. مرتب ڪندڙ ڏسي ٿو ته ڪنهن به قسم جي وضاحت نه ڪئي آهي، قسم کي اعتراض جي طور تي بيان ڪيو ويو آهي ۽ ڪوڊ جي عمل کي غلطي سان ناڪام ٿئي ٿو.
عام قسمون
توھان ٽائيپ ڪري سگھوٿا نه رڳو طريقا، پر پاڻ به ڪلاس. Oracle وٽ ھڪڙو " عام قسمون " سيڪشن آھي جيڪو انھن جي ھدايت ۾ وقف ڪيو ويو آھي. اچو ته هڪ مثال ڏسو:public static class SomeType<T> {
public <E> void test(Collection<E> collection) {
for (E element : collection) {
System.out.println(element);
}
}
public void test(List<Integer> collection) {
for (Integer element : collection) {
System.out.println(element);
}
}
}
هتي سڀ ڪجھ سادو آهي. جيڪڏهن اسان هڪ طبقي کي استعمال ڪندا آهيون، عام طبقي جي نالي کان پوء درج ٿيل آهي. اچو ته ھاڻي ھن طبقي جو ھڪڙو مثال ٺاھيون مکيه طريقي سان:
public static void main(String []args) {
SomeType<String> st = new SomeType<>();
List<String> list = Arrays.asList("test");
st.test(list);
}
اهو سٺو ڪم ڪندو. مرتب ڪندڙ ڏسندو آهي ته اتي انگن جي هڪ فهرست ۽ قسم جي String جو هڪ مجموعو آهي. پر ڇا جيڪڏهن اسان عام کي ختم ڪريون ٿا ۽ هي ڪندا آهيون:
SomeType st = new SomeType();
List<String> list = Arrays.asList("test");
st.test(list);
اسان کي غلطي ملندي: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
ٽائپ ڪريو erasure ٻيهر. جيئن ته ڪلاس ۾ هاڻي هڪ عام نه آهي، مرتب ڪندڙ اهو فيصلو ڪري ٿو ته جيئن اسان هڪ لسٽ پاس ڪيو آهي، هڪ طريقو List<Integer> سان وڌيڪ مناسب آهي. ۽ اسان هڪ غلطي سان ڪريون ٿا. تنهن ڪري، قاعدو # 2: جيڪڏهن هڪ ڪلاس ٽائيپ ڪيو ويو آهي، هميشه عام ۾ قسم بيان ڪريو .
پابنديون
اسان generics ۾ بيان ڪيل قسمن تي پابندي لاڳو ڪري سگھون ٿا. مثال طور، اسان چاهيون ٿا ته ڪنٽينر صرف نمبر ان پٽ طور قبول ڪري. هي خصوصيت بيان ڪيل آهي Oracle Tutorial in the Bounded Type Parameters سيڪشن . اچو ته هڪ مثال ڏسو:import java.util.*;
public class HelloWorld{
public static class NumberContainer<T extends Number> {
private T number;
public NumberContainer(T number) { this.number = number; }
public void print() {
System.out.println(number);
}
}
public static void main(String []args) {
NumberContainer number1 = new NumberContainer(2L);
NumberContainer number2 = new NumberContainer(1);
NumberContainer number3 = new NumberContainer("f");
}
}
جئين توهان ڏسي سگهو ٿا، اسان عام قسم کي محدود ڪيو آهي نمبر ڪلاس/انٽرفيس ۽ ان جو اولاد. دلچسپ ڳالهه اها آهي ته توهان وضاحت ڪري سگهو ٿا نه رڳو هڪ ڪلاس، پر انٽرفيس پڻ. مثال طور: public static class NumberContainer<T extends Number & Comparable> {
جنريڪس وٽ وائلڊ ڪارڊ جو تصور پڻ آهي https://docs.oracle.com/javase/tutorial/java/generics/wildcards.html اهي، موڙ ۾، ٽن قسمن ۾ ورهايل آهن:
- اپر بائونڊڊ وائلڊ ڪارڊ - < ؟ وڌايو نمبر >
- اڻڄاتل وائلڊ ڪارڊ - < ؟ >
- لوئر بائونڊڊ وائلڊ ڪارڊ - < ? سپر انٽيجر >
public static class TestClass {
public static void print(List<? extends String> list) {
list.add("Hello World!");
System.out.println(list.get(0));
}
}
public static void main(String []args) {
List<String> list = new ArrayList<>();
TestClass.print(list);
}
پر جيڪڏهن توهان سپر سان ايڪسپورٽ کي تبديل ڪريو، سڀ ڪجهه ٺيڪ ٿي ويندو. جيئن ته اسان ان کي ٻاھر ڪڍڻ کان اڳ ھڪڙي قيمت سان لسٽ ڀريندا آھيون، اھو اسان لاء ھڪڙو صارف آھي، اھو آھي، ھڪڙو صارف. تنهن ڪري، اسان سپر استعمال ڪندا آهيون.
وراثت
generics جي هڪ ٻي غير معمولي خصوصيت آهي - سندن وراثت. وراثت جي وراثت کي بيان ڪيو ويو آهي Oracle سبق ۾ سيڪشن ۾ " Generics، وراثت، ۽ ذيلي قسم ". بنيادي شيء ياد رکڻ ۽ هيٺ ڏنل احساس ڪرڻ آهي. اسان اهو نٿا ڪري سگهون:List<CharSequence> list1 = new ArrayList<String>();
ڇاڪاڻ ته وراثت عام سان مختلف ڪم ڪري ٿو:
List<String> list1 = new ArrayList<>();
List<Object> list2 = list1;
هتي پڻ سڀ ڪجهه سادو آهي. List<String> List<Object> جو اولاد نه آهي، جيتوڻيڪ String Object جو اولاد آهي.
GO TO FULL VERSION