JavaRush /جاوا بلاگ /Random-SD /جاوا ۾ generics جو نظريو يا عملي ۾ قوس ڪيئن رکڻ
Viacheslav
سطح

جاوا ۾ generics جو نظريو يا عملي ۾ قوس ڪيئن رکڻ

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

تعارف

JSE 5.0 سان شروع ڪندي، جاوا ٻولي جي هٿيارن ۾ عام شامل ڪيا ويا.
جاوا ۾ generics جو نظريو يا عملي ۾ قوس ڪيئن رکڻ - 1

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

Generics (generalizations) جاوا ٻوليءَ جا خاص وسيلا آھن عام پروگرامنگ کي لاڳو ڪرڻ لاءِ: ڊيٽا ۽ الگورتھم کي بيان ڪرڻ لاءِ ھڪڙو خاص طريقو جيڪو توھان کي اجازت ڏئي ٿو مختلف قسمن جي ڊيٽا سان ڪم ڪرڻ جي بغير انھن جي وضاحت کي تبديل ڪرڻ جي. Oracle ويب سائيٽ تي، هڪ الڳ سبق generics لاء وقف ڪيو ويو آهي: " سبق: عام ".

پهرين، عام کي سمجهڻ لاء، توهان کي سمجهڻ جي ضرورت آهي ڇو ته انهن سڀني جي ضرورت آهي ۽ اهي مهيا ڪن ٿا. سبق ۾ سيڪشن ۾ " جنريڪس ڇو استعمال ڪريو ؟" اهو چيو وڃي ٿو ته مقصدن مان هڪ آهي مضبوط مرتب وقت جي قسم جي چڪاس ۽ واضح طور تي ڪاسٽنگ جي ضرورت کي ختم ڪرڻ.
جاوا ۾ generics جو نظريو يا عملي ۾ قوس ڪيئن رکڻ - 2
اچو ته تيار ڪريون اسان جي پسنديده ٽيوٽوريل پوائنٽ آن لائن جاوا ڪمپلر تجربن لاءِ . اچو ته هن ڪوڊ کي تصور ڪريو:
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. اھو اسان کي ٻڌائيندو. ڪيترائي ماڻھو جنريڪس کي سڏيندا آھن "نحوي شگر". ۽ اهي صحيح آهن، ڇو ته عام طور تي اهي ساڳيون ذاتيون بڻجي وينديون آهن جڏهن مرتب ڪيو ويندو. اچو ته مرتب ڪيل طبقن جي بائيٽ ڪوڊ کي ڏسو: دستي ڪاسٽنگ ۽ عام استعمال سان:
جاوا ۾ generics جو نظريو يا عملي ۾ قوس ڪيئن رکڻ - 3
تاليف ڪرڻ کان پوء، generics بابت ڪا به ڄاڻ ختم ٿي ويندي آهي. اهو سڏيو ويندو آهي "قسم Erasure" يا " Type Erasure ". Type erasure ۽ generics کي JDK جي پراڻن ورزن سان پسمانده مطابقت مهيا ڪرڻ لاءِ تيار ڪيو ويو آهي، جڏهن ته اڃا تائين گڏ ڪرڻ واري کي اجازت ڏئي ٿي ته جاوا جي نئين ورزن ۾ قسم جي انفرنس ۾ مدد ڪري.
جاوا ۾ generics جو نظريو يا عملي ۾ قوس ڪيئن رکڻ - 4

خام قسم يا خام قسم

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

عام طريقا

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، يعني قسمون ختم ڪيون ويون آھن. مرتب ڪندڙ ڏسي ٿو ته ڪنهن به قسم جي وضاحت نه ڪئي آهي، قسم کي اعتراض جي طور تي بيان ڪيو ويو آهي ۽ ڪوڊ جي عمل کي غلطي سان ناڪام ٿئي ٿو.
Теория дженериков в Java or How на практике ставить скобки - 8

عام قسمون

توھان ٽائيپ ڪري سگھوٿا نه رڳو طريقا، پر پاڻ به ڪلاس. 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 اهي، موڙ ۾، ٽن قسمن ۾ ورهايل آهن: نام نهاد Get Put اصول لاڳو ٿئي ٿو وائلڊ ڪارڊز تي . اهي هيٺين صورت ۾ بيان ڪري سگهجي ٿو:
Теория дженериков в Java or How на практике ставить скобки - 9
هن اصول کي PECS (Producer Extends Consumer Super) اصول پڻ سڏيو ويندو آهي. توهان مضمون ۾ Habré تي وڌيڪ پڙهي سگهو ٿا “ جاوا API جي استعمال کي بهتر ڪرڻ لاءِ عام وائلڊ ڪارڊ استعمال ڪندي ”، انهي سان گڏ اسٽيڪ اوور فلو تي بهترين بحث ۾: “ جنريڪس جاوا ۾ وائلڊ ڪارڊ استعمال ڪندي ”. هتي جاوا ماخذ کان هڪ ننڍڙو مثال آهي - Collections.copy طريقو:
Теория дженериков в Java or How на практике ставить скобки - 10
خير، هڪ ننڍڙو مثال اهو ڪيئن ڪم نه ڪندو:
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>();
ڇاڪاڻ ته وراثت عام سان مختلف ڪم ڪري ٿو:
Теория дженериков в Java or How на практике ставить скобки - 11
۽ هتي هڪ ٻيو سٺو مثال آهي جيڪو هڪ غلطي سان ناڪام ٿيندو:
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