CodeGym /جاوا بلاگ /Random-SD /جاوا جنريڪس: ڪيئن استعمال ڪجي زاويه بریکٹ عملي ۾
John Squirrels
سطح
San Francisco

جاوا جنريڪس: ڪيئن استعمال ڪجي زاويه بریکٹ عملي ۾

گروپ ۾ شايع ٿيل

تعارف

JSE 5.0 سان شروع ڪندي، جاوا ٻولي جي هٿيارن ۾ عام شامل ڪيا ويا.

جاوا ۾ عام ڇا آهن؟

Generics جاوا جا خاص ميکانيزم آهن جنريڪ پروگرامنگ کي لاڳو ڪرڻ لاءِ — ڊيٽا ۽ الگورتھم کي بيان ڪرڻ جو هڪ طريقو جيڪو توهان کي مختلف ڊيٽا ٽائپس سان ڪم ڪرڻ جي اجازت ڏئي ٿو بغير الورورٿمز جي وضاحت کي تبديل ڪرڻ جي. Oracle ويب سائيٽ تي هڪ الڳ سبق آهي جيڪو generics لاء وقف ڪيو ويو آهي: " سبق ". عام سمجھڻ لاءِ، توھان کي پھريون ڄاڻڻ جي ضرورت آھي ته اھي ڇو گھرجن ۽ اھي ڇا ڏين. سبق جي " جنريڪس ڇو استعمال ڪريو؟ " سيڪشن ۾ چيو ويو آهي ته ٻه مقصد آهن مضبوط قسم جي چڪاس جي وقت تي گڏ ڪرڻ ۽ ختم ڪرڻ جي ضرورت کي ختم ڪرڻ. جاوا ۾ عامات: ڪيئن استعمال ڪجي زاويه بریکٹ عملي طور تي - 1اچو ته ڪجهه ٽيسٽن لاءِ تيار ڪريون اسان جي محبوب Tutorialspoint آن لائن جاوا ڪمپلر ۾. فرض ڪريو توھان وٽ ھيٺ ڏنل ڪوڊ آھي:
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);
	}
}
هي ڪوڊ تمام سٺو هلندو. پر ڇا جيڪڏهن باس اسان وٽ اچي ۽ چوي ته "هيلو، دنيا!" هڪ وڌيڪ استعمال ٿيل جملو آهي ۽ توهان کي صرف "هيلو" واپس ڪرڻ گهرجي؟ اسان اهو ڪوڊ هٽائي ڇڏينداسين جيڪو "، دنيا!" اهو ڪافي بي ضرر لڳي ٿو، صحيح؟ پر اسان اصل ۾ COMPILE TIME تي هڪ غلطي حاصل ڪندا آهيون:

error: incompatible types: Object cannot be converted to String
مسئلو اهو آهي ته اسان جي لسٽ ۾ شيون ذخيرو ڪري ٿو. اسٽرنگ آبجیکٹ جو اولاد آهي (جيئن ته سڀئي جاوا ڪلاس واضح طور تي وارث آهن Object )، جنهن جو مطلب آهي ته اسان کي هڪ واضح ڪاسٽ جي ضرورت آهي، پر اسان هڪ شامل نه ڪيو. Concatenation آپريشن دوران، static String.valueOf(obj) طريقي کي سڏيو ويندو اعتراض استعمال ڪندي. آخرڪار، اهو سڏيندو Object class's toString طريقو. ٻين لفظن ۾، اسان جي لسٽ ۾ هڪ اعتراض شامل آهي . هن جو مطلب اهو آهي ته جتي به اسان کي هڪ مخصوص قسم جي ضرورت آهي (نه Object )، اسان کي پاڻ کي قسم جي تبديلي کي ڪرڻو پوندو:
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);
		}
	}
}
بهرحال، هن حالت ۾، ڇاڪاڻ ته لسٽ شيون وٺي ٿي، اهو نه صرف اسٽرنگ s، پر انٽيجر s کي پڻ محفوظ ڪري سگهي ٿو. پر بدترين شيء اها آهي ته مرتب ڪندڙ هتي ڪجھ به غلط نه ڏسي. ۽ ھاڻي اسان کي رن ٽائم تي ھڪ نقص ملندو (جنھن کي ”رن ٽائم ايرر“ جي نالي سان سڃاتو ويندو). غلطي ٿيندي:

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
توهان کي متفق ٿيڻ گهرجي ته اهو تمام سٺو ناهي. ۽ اهو سڀ ڪجهه ڇاڪاڻ ته مرتب ڪندڙ هڪ مصنوعي ذهانت نه آهي هميشه هميشه پروگرامر جي ارادي جو صحيح اندازو لڳائڻ جي قابل. Java 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);
		}
	}
}
جيئن توهان ڏسي سگهو ٿا، اسان کي هاڻي ڪاسٽ جي ضرورت نه آهي اسٽرنگ ڏانهن . ان کان علاوه، اسان وٽ قسم جي دليل جي چوڌاري زاوي بریکٹس آهن. ھاڻي ڪمپائلر اسان کي ڪلاس کي گڏ ڪرڻ جي اجازت نه ڏيندو جيستائين اسان لسٽ ۾ 123 شامل ڪرڻ واري لائن کي ختم نه ڪندا، ڇو ته اھو ھڪڙو Integer آھي . ۽ اهو اسان کي ٻڌائيندو. ڪيترائي ماڻھو جنريڪس کي سڏيندا آھن "نحوي شگر". ۽ اهي صحيح آهن، ڇاڪاڻ ته عام طور تي مرتب ٿيڻ کان پوء، اهي حقيقت ۾ هڪ ئي قسم جي تبديلين بڻجي ويندا آهن. اچو ته مرتب ڪيل طبقن جي بائيٽ ڪوڊ تي نظر رکون: هڪ جيڪو واضح ڪاسٽ استعمال ڪري ٿو ۽ ٻيو جيڪو استعمال ڪري ٿو generics: جاوا ۾ عامات: ڪيئن استعمال ڪجي زاويه بریکٹ عملي طور تي - 2تاليف ڪرڻ کان پوء، سڀئي جنريڪس ختم ٿي ويا آهن. اهو سڏيو ويندو آهي " قسم erasure ". ٽائپ ايريسر ۽ جنريڪس ٺهيل آهن ته جيئن JDK جي پراڻن ورزن سان پسمانده مطابقت رکندڙ هجي جڏهن ته گڏو گڏ گڏ ڪرڻ واري کي اجازت ڏئي ٿي ته جاوا جي نئين ورزن ۾ قسم جي وصفن جي مدد ڪري.

خام قسمون

عام طور تي ڳالهائڻ، اسان وٽ هميشه ٻه ڀاڱا آهن: پيٽرولر ٿيل قسم ۽ خام قسم. خام قسم جا قسم آھن جيڪي "قسم جي وضاحت" کي ختم ڪن ٿا زاوي بریکٹ ۾: جاوا ۾ عامات: ڪيئن استعمال ڪجي زاويه بریکٹ عملي طور تي - 3پيرا ميٽر ٿيل قسم، ھٿ تي، "واضح ڪرڻ" شامل آھن: جاوا ۾ عامات: ڪيئن استعمال ڪجي زاويه بریکٹ عملي طور تي - 4جيئن توھان ڏسي سگھو ٿا، اسان ھڪڙو غير معمولي تعمير استعمال ڪيو آھي، اسڪرين شاٽ ۾ تير سان نشان لڳل آھي. ھي خاص نحو آھي جيڪو جاوا SE 7 ۾ شامل ڪيو ويو آھي. ان کي " ھيرا " سڏيو ويندو آھي. ڇو؟ زاويه بریکٹ هڪ هيرا ٺاهيندا آهن: <> . توهان کي اهو به ڄاڻڻ گهرجي ته هيرن جو نحو " قسم جو اندازو " جي تصور سان لاڳاپيل آهي . آخرڪار، مرتب ڪندڙ، <> ساڄي پاسي ڏسي، اسائنمينٽ آپريٽر جي کاٻي پاسي ڏسي ٿو، جتي اهو متغير جو قسم ڳولي ٿو جنهن جي قيمت مقرر ڪئي پئي وڃي. انهي جي بنياد تي جيڪو هن حصي ۾ ڳولي ٿو، اهو سمجهي ٿو ته ساڄي پاسي جي قيمت جو قسم. حقيقت ۾، جيڪڏهن هڪ عام قسم کاٻي پاسي ڏنو ويو آهي، پر ساڄي پاسي نه، مرتب ڪندڙ قسم جو اندازو لڳائي سگهي ٿو:
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") تشريح ڪنهن طريقي يا طبقي تي. پر سوچيو ته توهان ان کي استعمال ڪرڻ جو فيصلو ڪيو آهي. قاعدو نمبر هڪ ياد رکو. ٿي سگهي ٿو توهان کي هڪ قسم جي دليل شامل ڪرڻ جي ضرورت آهي.

جاوا عام طريقا

جنريڪس توهان کي طريقا ٺاهيندا آهن جن جي پيٽرولر جا قسم ۽ واپسي جو قسم پيٽرولر ٿيل آهن. 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));
		}
    }
}
جيڪڏهن توهان يوٽيل ڪلاس کي ڏسو ، توهان ڏسندا ته ان ۾ ٻه عام طريقا آهن. قسم جي انفرنس جي امڪان جي مهرباني، اسان يا ته قسم کي سڌو سنئون ڪمپيلر ڏانهن اشارو ڪري سگهون ٿا، يا اسان ان کي پاڻ بيان ڪري سگهون ٿا. ٻئي اختيار مثال ۾ پيش ڪيا ويا آهن. رستي جي ذريعي، نحو تمام گهڻو احساس ڪري ٿو جيڪڏهن توهان ان بابت سوچيو ٿا. جڏهن عام طريقي جو اعلان ڪريون ٿا، اسان طريقي کان پهريان قسم جي پيٽرولر کي بيان ڪريون ٿا، ڇاڪاڻ ته جيڪڏهن اسان طريقي سان قسم جي پيٽرولر جو اعلان ڪريون ٿا، ته JVM اهو معلوم ڪرڻ جي قابل نه هوندو ته ڪهڙي قسم کي استعمال ڪيو وڃي. ان جي مطابق، اسان پهريون اعلان ڪريون ٿا ته اسان استعمال ڪنداسين T قسم پيٽرولر، ۽ پوء اسان چئون ٿا ته اسان هن قسم کي واپس ڪرڻ وارا آهيون. قدرتي طور تي، Util.<Integer>getValue(عنصر، String.class) هڪ نقص سان ناڪام ٿيندو: نامناسب قسم: Class<String> کي 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);
اسان کي هڪ غلطي ملي ٿي:

bad operand types for binary operator '+', first type: Object, second type: int.
ٻين لفظن ۾، قسم ختم ٿي وئي آهي. مرتب ڪندڙ ڏسي ٿو ته ڪنهن به قسم جي وضاحت نه ڪئي آهي، تنهنڪري قسم کي اعتراض طور ظاهر ڪيو ويو آهي ۽ طريقو غلطي سان ناڪام ٿئي ٿو.

عام ڪلاس

نه رڳو طريقن parameterized ڪري سگهجي ٿو. ڪلاس پڻ ڪري سگهن ٿا. Oracle جي سبق جو "Generic Types" سيڪشن ھن لاءِ وقف آھي. اچو ته هڪ مثال تي غور ڪريو:
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);
}
هي ڪوڊ سٺو هلندو. مرتب ڪندڙ ڏسي ٿو ته اتي انگن جي هڪ فهرست ۽ اسٽرنگ جو هڪ مجموعو آهي . پر ڇا جيڪڏهن اسان ٽائيپ پيٽرولر کي ختم ڪريون ٿا ۽ هي ڪريو ٿا:
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 پاس ڪيو آهي، List<Integer> سان طريقو سڀ کان مناسب آهي. ۽ اسان هڪ غلطي سان ناڪام آهيون. تنهن ڪري، اسان وٽ آهي قاعدو # 2: جيڪڏهن توهان وٽ هڪ عام ڪلاس آهي، هميشه قسم جي پيراگراف بيان ڪريو.

پابنديون

اسان عام طريقن ۽ ڪلاسن ۾ بيان ڪيل قسمن کي محدود ڪري سگھون ٿا. مثال طور، فرض ڪريو اسان هڪ ڪنٽينر چاهيون ٿا ته صرف هڪ نمبر قبول ڪري قسم جي دليل طور. ھي مضمون بيان ڪيل آھي Bounded Type Parameters سيڪشن Oracle جي سبق ۾. اچو ته هڪ مثال ڏسو:
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> {
جنريڪس به وائلڊ ڪارڊ جي حمايت ڪن ٿا اهي ٽن قسمن ۾ ورهايل آهن: توهان جي وائلڊ ڪارڊ جو استعمال Get-Put جي اصول تي عمل ڪرڻ گهرجي . اهو هن ريت بيان ڪري سگهجي ٿو:
  • وڌايل وائلڊ ڪارڊ استعمال ڪريو جڏھن توھان صرف قدر حاصل ڪريو ھڪڙي ساخت مان.
  • سپر وائلڊ ڪارڊ استعمال ڪريو جڏھن توھان صرف قدرن کي ھڪڙي جوڙجڪ ۾ وجھو.
  • ۽ وائلڊ ڪارڊ استعمال نه ڪريو جڏهن توهان ٻئي ڪنهن ڍانچي مان حاصل ڪرڻ ۽ رکڻ چاهيو ٿا.
ان اصول کي پروڊيوسر Extends Consumer Super (PECS) اصول پڻ سڏيو ويندو آهي. هتي جاوا جي Collections.copy طريقي لاءِ سورس ڪوڊ مان هڪ ننڍڙو مثال آهي : جاوا ۾ عامات: ڪيئن استعمال ڪجي زاويه بریکٹ عملي طور تي - 5۽ هتي هڪ ننڍڙو مثال آهي جيڪو ڪم نه ڪندو:
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);
}
پر جيڪڏھن توھان مٽايو extras سان ، پوء سڀ ڪجھ ٺيڪ آھي. ڇاڪاڻ ته اسان فهرست کي ان جي مواد کي ظاهر ڪرڻ کان پهريان قيمت سان ڀريندا آهيون، اهو هڪ صارف آهي . انهي جي مطابق، اسان سپر استعمال ڪندا آهيون.

وراثت

جنريڪس هڪ ٻي دلچسپ خصوصيت آهي: وراثت. وراثت جو طريقو generics لاءِ ڪم ڪري ٿو " Generics, Inheritance, and Subtypes " هيٺ Oracle جي سبق ۾ بيان ڪيو ويو آهي. اھم ڳالھھ ھيٺ ڏنل ياد رکڻ ۽ سڃاڻڻ آھي. اسان اهو نٿا ڪري سگهون:
List<CharSequence> list1 = new ArrayList<String>();
ڇاڪاڻ ته وراثت عام سان مختلف ڪم ڪري ٿو: جاوا ۾ عامات: ڪيئن استعمال ڪجي زاويه بریکٹ عملي طور تي - 6۽ هتي هڪ ٻيو سٺو مثال آهي جيڪو غلطي سان ناڪام ٿيندو:
List<String> list1 = new ArrayList<>();
List<Object> list2 = list1;
ٻيهر، هتي هر شيء سادو آهي. List<String> List<Object> جو اولاد نه آهي ، جيتوڻيڪ String Object جو اولاد آهي . جيڪو توهان سکيو ان کي مضبوط ڪرڻ لاءِ، اسان توهان کي اسان جي جاوا ڪورس مان هڪ وڊيو سبق ڏسڻ جي صلاح ڏيون ٿا
تنهنڪري اسان پنهنجي يادگيري کي تازو ڪيو آهي عام بابت. جيڪڏهن توهان گهٽ ۾ گهٽ انهن جي صلاحيتن جو پورو فائدو وٺو، ڪجهه تفصيلن منجهيل وڌندا آهن. مون کي اميد آهي ته هي مختصر جائزو توهان جي يادگيري کي جاڳائڻ ۾ مدد ڪئي آهي. اڃا به بهتر نتيجا حاصل ڪرڻ لاءِ، مان سختي سان صلاح ڏيان ٿو ته توهان پاڻ کي هيٺين مواد سان واقف ڪيو:
تبصرا
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION