JavaRush /جاوا بلاگ /Random-SD /ٻلين لاءِ عام
Viacheslav
سطح

ٻلين لاءِ عام

گروپ ۾ شايع ٿيل
ٻلين لاءِ عام شيون - 1

تعارف

اڄ هڪ بهترين ڏينهن آهي ياد رکڻ لاءِ جيڪو اسان ڄاڻون ٿا جاوا بابت. سڀ کان اهم دستاويز موجب، i.e. Java Language Specification (JLS - Java Language Specifiaction)، Java هڪ مضبوط ٽائپ ڪيل ٻولي آهي، جيئن باب 4. قسم، قدر، ۽ متغيرات ۾ بيان ڪيل آهي . هن جو مطلب ڇا آهي؟ اچو ته اسان وٽ ھڪڙو مکيه طريقو آھي:
public static void main(String[] args) {
String text = "Hello world!";
System.out.println(text);
}
مضبوط ٽائپنگ انهي ڳالهه کي يقيني بڻائي ٿي ته جڏهن هي ڪوڊ مرتب ڪيو ويندو ته ڪمپلر چيڪ ڪندو ته جيڪڏهن اسان ٽيڪسٽ ويريئبل جي قسم کي String طور بيان ڪيو آهي ته پوءِ اسان ان کي ڪٿي به استعمال ڪرڻ جي ڪوشش نه ڪري رهيا آهيون ڪنهن ٻئي قسم جي متغير طور (مثال طور، هڪ Integer) . مثال طور، جيڪڏهن اسان ٽيڪسٽ جي بدران قيمت بچائڻ جي ڪوشش ڪندا آهيون 2L(يعني اسٽرنگ جي بدران ڊگهو)، اسان کي گڏ ڪرڻ وقت هڪ غلطي ملندي:

Main.java:3: error: incompatible types: long cannot be converted to String
String text = 2L;
اهي. مضبوط ٽائپنگ توهان کي اها پڪ ڪرڻ جي اجازت ڏئي ٿي ته شين تي آپريشن صرف تڏهن ڪيا ويندا آهن جڏهن اهي آپريشن انهن شين لاءِ قانوني هجن. اهو پڻ سڏيو ويندو آهي قسم جي حفاظت. جيئن ته JLS ۾ چيو ويو آهي، جاوا ۾ قسم جا ٻه قسم آهن: ابتدائي قسم ۽ حوالن جا قسم. توهان جائزو وٺڻ واري آرٽيڪل مان ابتدائي قسمن جي باري ۾ ياد ڪري سگهو ٿا: " جاوا ۾ ابتدائي قسمون: اهي ايترو ابتدائي نه آهن ." حوالن جا قسم ڪلاس، انٽرفيس، يا صف جي نمائندگي ڪري سگھن ٿا. ۽ اڄ اسان کي حوالن جي قسمن ۾ دلچسپي وٺندي. ۽ اچو ته صفن سان شروع ڪريون:
class Main {
  public static void main(String[] args) {
    String[] text = new String[5];
    text[0] = "Hello";
  }
}
هي ڪوڊ بغير ڪنهن غلطي جي هلندو آهي. جيئن اسان ڄاڻون ٿا (مثال طور، " Oracle Java Tutorial: Arrays " مان)، هڪ صف هڪ ڪنٽينر آهي جيڪو صرف هڪ قسم جي ڊيٽا کي محفوظ ڪري ٿو. هن معاملي ۾ - صرف سٽون. اچو ته ڪوشش ڪريون لانگ کي String جي بدران صف ۾ شامل ڪرڻ:
text[1] = 4L;
اچو ته هن ڪوڊ کي هلون (مثال طور، Repl.it آن لائن جاوا ڪمپلر ۾ ) ۽ غلطي حاصل ڪريو:
error: incompatible types: long cannot be converted to String
ٻوليء جي صف ۽ قسم جي حفاظت اسان کي هڪ صف ۾ محفوظ ڪرڻ جي اجازت نه ڏني جيڪا قسم جي مطابق نه هئي. هي قسم جي حفاظت جو هڪ مظهر آهي. اسان کي ٻڌايو ويو: "غلطي کي درست ڪريو، پر ان وقت تائين مان ڪوڊ مرتب نه ڪندس." ۽ ان جي باري ۾ سڀ کان اهم شيء اها آهي ته اهو تاليف جي وقت ٿئي ٿو، ۽ نه جڏهن پروگرام شروع ڪيو ويو آهي. اهو آهي، اسان کي فوري طور تي غلطيون نظر اچن ٿا، ۽ نه "ڪنهن ڏينهن." ۽ جيئن ته اسان arrays بابت ياد ڪيو، اچو ته جاوا ڪليڪشن فريم ورڪ جي باري ۾ پڻ ياد رکون . اسان وٽ اتي مختلف اڏاوتون هيون. مثال طور، فهرستون. اچو ته مثال ٻيهر لکون:
import java.util.*;
class Main {
  public static void main(String[] args) {
    List text = new ArrayList(5);
    text.add("Hello");
    text.add(4L);
    String test = text.get(0);
  }
}
testجڏهن ان کي گڏ ڪندي، اسان کي متغير شروعاتي لائن تي هڪ غلطي ملندي :
incompatible types: Object cannot be converted to String
اسان جي صورت ۾، فهرست ڪنهن به شئي کي ذخيرو ڪري سگھي ٿو (يعني قسم جو اعتراض). تنهن ڪري، مرتب ڪندڙ چوي ٿو ته اها ذميواري جي اهڙي بار تي نه ٿي سگهي. تنهن ڪري، اسان کي واضح طور تي بيان ڪرڻ جي ضرورت آهي ته اسان فهرست مان حاصل ڪنداسين:
String test = (String) text.get(0);
ھن اشاري کي ٽائپ ڪنورشن يا ٽائيپ ڪاسٽنگ چئبو آھي. ۽ سڀ ڪجھ ٺيڪ ڪم ڪندو ھاڻي جيستائين اسان انڊيڪس 1 تي عنصر حاصل ڪرڻ جي ڪوشش نه ڪنداسين، ڇاڪاڻ ته اهو ڊگهو قسم جو آهي. ۽ اسان کي هڪ مناسب غلطي ملندي، پر اڳ ۾ ئي جڏهن پروگرام هلي رهيو آهي (رن ٽائم ۾):

type conversion, typecasting
Exception in thread "main" java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.String
جيئن اسان ڏسي سگهون ٿا، هتي ڪيترائي اهم نقصان آهن. پهرين، اسان کي "ڪاسٽ" ڪرڻ تي مجبور ڪيو وڃي ٿو حاصل ڪيل قيمت کي لسٽ مان اسٽرنگ ڪلاس ڏانهن. اتفاق ڪيو، هي بدصورت آهي. ٻيو، غلطي جي صورت ۾، اسان ان کي صرف ان وقت ڏسندا سين جڏهن پروگرام تي عمل ڪيو ويندو. جيڪڏهن اسان جو ڪوڊ وڌيڪ پيچيده هو، ته اسان شايد اهڙي غلطي کي فوري طور تي نه ڳولي سگهون. ۽ ڊولپر سوچڻ شروع ڪيو ته اهڙين حالتن ۾ ڪم کي ڪيئن آسان بڻائي سگهجي ٿو ۽ ڪوڊ وڌيڪ واضح. ۽ اھي پيدا ٿيا - Generics.
ٻلين لاءِ عام شيون - 2

عام

تنهن ڪري، عام. اهو ڇا آهي؟ عام استعمال ٿيل قسمن کي بيان ڪرڻ جو ھڪڙو خاص طريقو آھي، جنھن کي ڪوڊ مرتب ڪندڙ پنھنجي ڪم ۾ استعمال ڪري سگھي ٿو قسم جي حفاظت کي يقيني بڻائڻ لاء. اهو ڪجهه هن طرح نظر اچي ٿو:
ٻلين لاءِ عام - 3
هتي هڪ مختصر مثال ۽ وضاحت آهي:
import java.util.*;
class Main {
  public static void main(String[] args) {
    List<String> text = new ArrayList<String>(5);
    text.add("Hello");
    text.add(4L);
    String test = text.get(1);
  }
}
هن مثال ۾، اسان چئون ٿا ته اسان وٽ صرف نه آهي List، پر List، جيڪو صرف String قسم جي شين سان ڪم ڪري ٿو. ۽ ٻيو نه. ڇا صرف بریکٹ ۾ اشارو ڪيو ويو آهي، اسان ان کي ذخيرو ڪري سگهون ٿا. اهڙيون "بریکٹس" کي "زاوي بریکٹ" سڏيو ويندو آهي، يعني. زاويه بریکٹ. مرتب ڪندڙ مهرباني ڪري اسان لاءِ چيڪ ڪندو ته ڇا اسان تارن جي فهرست سان ڪم ڪرڻ وقت ڪا غلطي ڪئي آهي (فهرست کي متن جو نالو ڏنو ويو آهي). مرتب ڪندڙ ڏسندو ته اسان بيحد ڪوشش ڪري رهيا آهيون لانگ کي اسٽرنگ لسٽ ۾. ۽ تاليف جي وقت تي اهو هڪ غلطي ڏيندو:
error: no suitable method found for add(long)
توهان کي ياد هوندو ته String CharSequence جو اولاد آهي. ۽ ڪجهه ڪرڻ جو فيصلو ڪيو جيئن:
public static void main(String[] args) {
	ArrayList<CharSequence> text = new ArrayList<String>(5);
	text.add("Hello");
	String test = text.get(0);
}
پر اهو ممڪن ناهي ۽ اسان کي غلطي ملندي: error: incompatible types: ArrayList<String> cannot be converted to ArrayList<CharSequence> اهو عجيب لڳي ٿو، ڇاڪاڻ ته. لائن CharSequence sec = "test";۾ ڪا به غلطي نه آهي. اچو ته ان جو اندازو لڳايو. اهي هن رويي جي باري ۾ چوندا آهن: "جنريڪس غير متغير آهن." هڪ "invariant" ڇا آهي؟ مون کي پسند آهي ته ان بابت وڪيپيڊيا تي مضمون ” Covariance and contravariance ” ۾ ڪيئن چيو ويو آهي:
ٻلين لاءِ عام - 4
اهڙيء طرح، Invariance نڪتل قسمن جي وچ ۾ وراثت جي غير موجودگي آهي. جيڪڏهن ٻلي جانورن جو ذيلي قسم آهي، ته پوءِ سيٽ<Cats> سيٽ<Animals> جو ذيلي قسم نه آهي ۽ سيٽ<جانور> سيٽ<Cats> جو ذيلي قسم ناهي. رستي جي ذريعي، اهو چوڻ جي قابل آهي ته جاوا SE 7 سان شروع ڪندي، جنهن کي " هيرن آپريٽر " سڏيو ويندو آهي. ڇاڪاڻ ته ٻه زاويه بریکٹ <> هيرن وانگر آهن. هي اسان کي اجازت ڏئي ٿو ته جيئن عام استعمال ڪريو:
public static void main(String[] args) {
  List<String> lines = new ArrayList<>();
  lines.add("Hello world!");
  System.out.println(lines);
}
هن ڪوڊ جي بنياد تي، ڪمپلر سمجهي ٿو ته جيڪڏهن اسان کاٻي پاسي اشارو ڪيو ته ان ۾ ListString قسم جون شيون هونديون، ته پوءِ ساڄي پاسي اسان جو مطلب اهو آهي ته اسان linesهڪ نئين ArrayList کي هڪ variable ۾ محفوظ ڪرڻ چاهيون ٿا، جيڪو پڻ هڪ اعتراض کي ذخيرو ڪندو. کاٻي پاسي بيان ڪيل قسم جو. تنهن ڪري کاٻي پاسي کان مرتب ڪندڙ ساڄي پاسي واري قسم کي سمجهي ٿو يا ان کي بيان ڪري ٿو. اهو ئي سبب آهي ته ان رويي کي انگريزيءَ ۾ ٽائپ انفرنس يا ”Type Inference“ چئبو آهي. هڪ ٻي دلچسپ شيءِ قابل غور آهي RAW Types يا ”خام قسم“. ڇاڪاڻ ته جنريڪس هميشه ڀرسان نه هوندا آهن، ۽ جاوا جڏهن ممڪن هجي ته پسمانده مطابقت برقرار رکڻ جي ڪوشش ڪري، پوء جنريڪس کي مجبور ڪيو وڃي ٿو ڪنهن به طريقي سان ڪم ڪرڻ لاء ڪوڊ سان جتي ڪو به عام بيان نه ڪيو ويو آهي. اچو ته هڪ مثال ڏسون:
List<CharSequence> lines = new ArrayList<String>();
جيئن ته اسان کي ياد آهي، اهڙي لڪير کي ترتيب نه ڏيندو generics جي invariance جي ڪري.
List<Object> lines = new ArrayList<String>();
۽ هي هڪ به گڏ نه ڪندو، ساڳئي سبب لاء.
List lines = new ArrayList<String>();
List<String> lines2 = new ArrayList();
اهڙيون لڪيرون گڏ ڪنديون ۽ ڪم ڪنديون. اهو انهن ۾ آهي ته خام قسم استعمال ڪيا ويا آهن، يعني. اڻ ڄاڻايل قسم. هڪ ڀيرو ٻيهر، اهو اشارو ڏيڻ جي قابل آهي ته خام قسمون جديد ڪوڊ ۾ استعمال نه ٿيڻ گهرجن.
ٻلين لاءِ عام - 5

ٽائپ ٿيل ڪلاس

تنهن ڪري، ٽائپ ٿيل ڪلاس. اچو ته ڏسون ته اسان پنهنجو ٽائپ ڪيل ڪلاس ڪيئن لکي سگهون ٿا. مثال طور، اسان وٽ هڪ طبقي جو درجو آهي:
public static abstract class Animal {
  public abstract void voice();
}

public static class Cat extends Animal {
  public void voice(){
    System.out.println("Meow meow");
  }
}

public static class Dog extends Animal {
  public void voice(){
    System.out.println("Woof woof");
  }
}
اسان هڪ ڪلاس ٺاهڻ چاهيون ٿا جيڪو هڪ جانور ڪنٽينر کي لاڳو ڪري ٿو. اهو ممڪن آهي ته هڪ ڪلاس لکڻ لاء جنهن ۾ ڪنهن به هجي Animal. اهو سادو آهي، سمجھڻ وارو، پر... ڪتن ۽ ٻليون کي گڏ ڪرڻ خراب آهي، اهي هڪ ٻئي جا دوست نه آهن. ان کان علاوه، جيڪڏهن ڪنهن کي اهڙو ڪنٽينر ملي ٿو، ته هو غلطيءَ سان ڪنٽينر مان ٻڪرين کي ڪتن جي ٿلهي ۾ اڇلائي سگهي ٿو ... ۽ ان سان ڪو به فائدو نه ٿيندو. ۽ هتي generics اسان جي مدد ڪندو. مثال طور، اچو ته عمل کي هن طرح لکون:
public static class Box<T> {
  List<T> slots = new ArrayList<>();
  public List<T> getSlots() {
    return slots;
  }
}
اسان جو ڪلاس ڪم ڪندو ان قسم جي شين سان، جنهن کي عام طور تي T جي نالي سان بيان ڪيو ويو آهي. هي هڪ قسم جو عرف آهي. ڇاڪاڻ ته عام کي ڪلاس جي نالي ۾ بيان ڪيو ويو آهي، پوء اسان ان کي حاصل ڪنداسين جڏهن ڪلاس جو اعلان ڪندي:
public static void main(String[] args) {
  Box<Cat> catBox = new Box<>();
  Cat murzik = new Cat();
  catBox.getSlots().add(murzik);
}
جيئن اسان ڏسي سگهون ٿا، اسان اشارو ڪيو ته اسان وٽ آهي Box، جيڪو صرف ڪم ڪري ٿو Cat. مرتب ڪندڙ محسوس ڪيو ته catBoxعام جي بدران، Tتوهان کي قسم کي متبادل ڪرڻ جي ضرورت آهي Catجتي عام جو نالو بيان ڪيو ويو آهي T:
ٻلين لاءِ عام شيون - 6
اهي. اهو Box<Cat>ڪمپيلر جي مهرباني آهي ته اهو سمجهي ٿو ته slotsاهو اصل ۾ هجڻ گهرجي List<Cat>. ڇاڪاڻ ته Box<Dog>اندر هوندو slots، مشتمل هوندو List<Dog>. ھڪڙي قسم جي بيان ۾ ڪيترائي عام ٿي سگھن ٿا، مثال طور:
public static class Box<T, V> {
عام نالو ڪجهه به ٿي سگهي ٿو، جيتوڻيڪ اهو ڪجهه اڻ ٻڌايل قاعدن تي عمل ڪرڻ جي سفارش ڪئي وئي آهي - "ٽائپ پيراميٽر نامنگ ڪنوينشن": عنصر جو قسم - E، ڪيئي قسم - K، نمبر جو قسم - N، T - قسم لاءِ، V - قدر جي قسم لاءِ . رستي ۾، ياد رکو ته اسان چيو ته generics invariant آهن، i.e. وراثت واري درجي کي محفوظ نه ڪريو. حقيقت ۾، اسان هن تي اثر انداز ڪري سگهون ٿا. اهو آهي، اسان وٽ generics COvariant ٺاهڻ جو موقعو آهي، يعني. وراثت کي ساڳئي ترتيب ۾ رکڻ. هن رويي کي سڏيو ويندو آهي "Bounded Type"، يعني. محدود قسمن. مثال طور، اسان جي ڪلاس ۾ Boxسڀني جانورن تي مشتمل ٿي سگھي ٿو، پوء اسين هن طرح عام بيان ڪنداسين:
public static class Box<T extends Animal> {
اھو آھي، اسان ڪلاس تائين مٿئين حد مقرر ڪيو Animal. اسان لفظ جي پٺيان ڪيترن ئي قسمن جي وضاحت ڪري سگھون ٿا extends. هن جو مطلب اهو ٿيندو ته اسان جنهن قسم سان ڪم ڪنداسين اهو ڪنهن طبقي جو اولاد هجڻ گهرجي ۽ ساڳئي وقت ڪجهه انٽرفيس کي لاڳو ڪرڻ گهرجي. مثال طور:
public static class Box<T extends Animal & Comparable> {
انهي صورت ۾، جيڪڏهن اسان Boxڪجهه اهڙي شيء ۾ رکڻ جي ڪوشش ڪندا آهيون جيڪو وارث نه آهي Animal۽ عمل نٿو ڪري Comparable، پوء گڏ ڪرڻ دوران اسان کي هڪ غلطي ملندي:
error: type argument Cat is not within bounds of type-variable T
ٻلين لاءِ عام - 7

ٽائپنگ جو طريقو

جنريڪس استعمال نه رڳو قسمن ۾، پر انفرادي طريقن ۾ پڻ. طريقن جي ايپليڪيشن کي سرڪاري ٽيوٽوريل ۾ ڏسي سگھجي ٿو: " عام طريقا ".

پس منظر:

ٻلين لاءِ عام - 8
اچو ته هن تصوير کي ڏسو. جئين توهان ڏسي سگهو ٿا، مرتب ڪندڙ طريقي جي دستخط کي ڏسي ٿو ۽ ڏسي ٿو ته اسان ڪجهه اڻ ڄاڻايل ڪلاس کي ان پٽ طور وٺي رهيا آهيون. اهو دستخط ذريعي طئي نٿو ڪري ته اسان ڪنهن قسم جي اعتراض کي واپس ڪري رهيا آهيون، يعني. اعتراض. تنهن ڪري، جيڪڏهن اسان ٺاهڻ چاهيون ٿا، چئو، هڪ ArrayList، پوء اسان کي اهو ڪرڻو پوندو:
ArrayList<String> object = (ArrayList<String>) createObject(ArrayList.class);
توهان کي واضح طور تي لکڻو پوندو ته آئوٽ هڪ ArrayList هوندو، جيڪو بدصورت آهي ۽ غلطي ڪرڻ جو هڪ موقعو وڌائيندو آهي. مثال طور، اسان اهڙي بيوقوف لکي سگهون ٿا ۽ اهو ترتيب ڏيندو:
ArrayList object = (ArrayList) createObject(LinkedList.class);
ڇا اسان ڪمپيلر جي مدد ڪري سگھون ٿا؟ ها، جنريڪس اسان کي اهو ڪرڻ جي اجازت ڏين ٿا. اچو ته ساڳيو مثال ڏسو:
ٻلين لاءِ عام - 9
ان کان پوء، اسان هڪ اعتراض ٺاهي سگهون ٿا صرف هن طرح:
ArrayList<String> object = createObject(ArrayList.class);
ٻلين لاءِ عام - 10

وائلڊ ڪارڊ

جينريڪس تي Oracle جي سبق جي مطابق، خاص طور تي " وائلڊ ڪارڊ " سيڪشن، اسان وضاحت ڪري سگھون ٿا "اڻڄاتل قسم" کي سوال جي نشان سان. وائلڊ ڪارڊ هڪ ڪارائتو اوزار آهي ته جيئن جنريڪس جي ڪجهه حدن کي گهٽائڻ لاءِ. مثال طور، جيئن اسان اڳ ۾ بحث ڪيو، generics invariant آهن. هن جو مطلب اهو آهي ته جيتوڻيڪ سڀئي طبقن جي اولاد (ذيلي قسم) آبجیکٹ جي قسم جا آهن، اهو List<любой тип>هڪ ذيلي قسم ناهي List<Object>. پر، List<любой тип>اهو هڪ ذيلي قسم آهي List<?>. تنهنڪري اسان هيٺ ڏنل ڪوڊ لکي سگهون ٿا:
public static void printList(List<?> list) {
  for (Object elem: list) {
    System.out.print(elem + " ");
  }
  System.out.println();
}
عام جنريڪس وانگر (يعني وائلڊ ڪارڊ جي استعمال کان سواءِ)، وائلڊ ڪارڊ سان جنريڪس محدود ٿي سگهن ٿا. اپر بائونڊڊ وائلڊ ڪارڊ واقف نظر اچي ٿو:
public static void printCatList(List<? extends Cat> list) {
  for (Cat cat: list) {
    System.out.print(cat + " ");
  }
  System.out.println();
}
پر توھان ان کي محدود ڪري سگھوٿا لوئر بائونڊ وائلڊ ڪارڊ ذريعي:
public static void printCatList(List<? super Cat> list) {
اهڙيء طرح، طريقو سڀني ٻلين کي قبول ڪرڻ شروع ڪيو ويندو، انهي سان گڏ اعلي درجي ۾ (آبجج تائين).
ٻلين لاءِ عام - 11

قسم Erasure

عام جي باري ۾ ڳالهائيندي، اهو ڄاڻڻ جي قابل آهي "قسم کي ختم ڪرڻ" بابت. حقيقت ۾، قسم erasure حقيقت جي باري ۾ آهي ته generics compiler لاء معلومات آهن. پروگرام جي عمل جي دوران، عام جي باري ۾ وڌيڪ ڄاڻ نه آهي، ان کي "ختم" سڏيو ويندو آهي. هي erasure اهو اثر آهي ته عام قسم کي مخصوص قسم سان تبديل ڪيو ويندو آهي. جيڪڏهن عام کي حد نه هئي، پوء اعتراض جو قسم متبادل ڪيو ويندو. جيڪڏهن سرحد بيان ڪئي وئي هئي (مثال طور <T extends Comparable>)، پوء ان کي متبادل بڻايو ويندو. هتي Oracle جي سبق مان هڪ مثال آهي: " عام قسمن جو خاتمو ":
ٻلين لاءِ عام - 12
جيئن مٿي چيو ويو آهي، هن مثال ۾ عام Tان جي سرحد کي ختم ڪيو ويو آهي، يعني. اڳ Comparable_
ٻلين لاءِ عام - 13

نتيجو

Generics هڪ تمام دلچسپ موضوع آهي. مون کي اميد آهي ته هي موضوع توهان جي دلچسپي جو آهي. اختصار ڪرڻ لاءِ، اسان اهو چئي سگهون ٿا ته generics هڪ بهترين اوزار آهي جيڪو ڊولپرز حاصل ڪيو آهي مرتب ڪندڙ کي اضافي معلومات سان گڏ هڪ طرف قسم جي حفاظت ۽ ٻئي طرف لچڪ کي يقيني بڻائڻ لاءِ. ۽ جيڪڏھن توھان چاھيو ٿا، ته مان توھان کي صلاح ڏيان ٿو ته توھان انھن وسيلن کي چيڪ ڪريو جيڪي مون پسند ڪيو: #وياچسلاو
تبصرا
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION