नमस्ते! आइए जेनरिक के अपने अध्ययन को जारी रखें। आप पिछले पाठों से उनके बारे में पर्याप्त ज्ञान प्राप्त कर चुके हैं ( जेनरिक के साथ काम करते समय varargs का उपयोग करने के बारे में और टाइप इरेज़र के बारे में ), लेकिन एक महत्वपूर्ण विषय है जिस पर हमने अभी तक विचार नहीं किया है - वाइल्डकार्ड । यह जेनरिक की बहुत महत्वपूर्ण विशेषता है। इतना अधिक कि हमने इसके लिए एक अलग पाठ समर्पित किया है! उस ने कहा, वाइल्डकार्ड के बारे में विशेष रूप से जटिल कुछ भी नहीं है। आप इसे तुरंत देखेंगे :)
आइए एक उदाहरण देखें:
लेकिन अब आइए एक अलग स्थिति देखें। हमारी वंशानुक्रम पदानुक्रम अपरिवर्तित रहता है: शीर्ष-स्तरीय वर्ग है

public class Main {
public static void main(String[] args) {
String str = new String("Test!");
// No problem
Object obj = str;
List<String> strings = new ArrayList<String>();
// Compilation error!
List<Object> objects = strings;
}
}
यहाँ क्या चल रहा है? हम दो बहुत ही समान स्थितियों को देखते हैं। मामले में, हम किसी String
वस्तु को किसी Object
वस्तु में डालते हैं। यहां कोई समस्या नहीं है — सब कुछ उम्मीद के मुताबिक काम करता है। लेकिन दूसरी स्थिति में, कंपाइलर त्रुटि उत्पन्न करता है। लेकिन हम वही कर रहे हैं, है ना? इस बार हम बस कई वस्तुओं के संग्रह का उपयोग कर रहे हैं। लेकिन त्रुटि क्यों होती है? क्या फर्क पड़ता है? क्या हम एक वस्तु को एक या 20 वस्तुओं String
पर कास्ट कर रहे हैं? किसी वस्तु और वस्तुओं के संग्रहObject
के बीच एक महत्वपूर्ण अंतर है । यदि कक्षा कक्षा की संतान है , तो कक्षा की संतान नहीं है । यही कारण है कि हम अपने को a में कास्ट नहीं कर पाएB
A
Collection<B>
Collection<A>
List<String>
List<Object>
. String
की संतान है Object
, लेकिन List<String>
की संतान नहीं है List<Object>
। यह अति सहज ज्ञान युक्त नहीं लग सकता है। भाषा के रचनाकारों ने इसे ऐसा क्यों बनाया? आइए कल्पना करें कि संकलक हमें कोई त्रुटि नहीं देता है:
List<String> strings = new ArrayList<String>();
List<Object> objects = strings;
इस मामले में, हम, उदाहरण के लिए, निम्नलिखित कर सकते हैं:
objects.add(new Object());
String s = strings.get(0);
क्योंकि संकलक ने हमें कोई त्रुटि नहीं दी और हमें एक List<Object>
संदर्भ बनाने की अनुमति दी जो इंगित करता है strings
, हम संग्रह Object
में कोई भी पुरानी वस्तु जोड़ सकते हैं strings
! इस प्रकार, हमने गारंटी खो दी है कि हमारे संग्रह में केवल String
सामान्य प्रकार के आमंत्रण में प्रकार तर्क द्वारा निर्दिष्ट वस्तुएं शामिल हैं । दूसरे शब्दों में, हमने जेनरिक-टाइप सुरक्षा का मुख्य लाभ खो दिया है। और क्योंकि कंपाइलर ने हमें ऐसा करने से नहीं रोका, हमें केवल रन टाइम पर एक त्रुटि मिलेगी, जो हमेशा एक संकलन त्रुटि से बहुत खराब होती है। इस तरह की स्थितियों को रोकने के लिए, कंपाइलर हमें एक एरर देता है:
// Compilation error
List<Object> objects = strings;
...और हमें याद दिलाता है कि List<String>
का वंशज नहीं है List<Object>
। यह जेनरिक के लिए एक दृढ़ नियम है, और उनके साथ काम करते समय इसे याद रखना चाहिए। पर चलते हैं। मान लीजिए कि हमारे पास एक छोटा वर्ग पदानुक्रम है:
public class Animal {
public void feed() {
System.out.println("Animal.feed()");
}
}
public class Pet extends Animal {
public void call() {
System.out.println("Pet.call()");
}
}
public class Cat extends Pet {
public void meow() {
System.out.println("Cat.meow()");
}
}
पदानुक्रम एक साधारण पशु वर्ग द्वारा सबसे ऊपर है, जो पेट द्वारा विरासत में मिला है। पालतू जानवरों के 2 उपवर्ग होते हैं: कुत्ता और बिल्ली। अब मान लीजिए कि हमें एक सरल iterateAnimals()
विधि बनाने की आवश्यकता है। Animal
विधि को किसी भी जानवर ( ,,,, ) का संग्रह लेना चाहिए , सभी तत्वों पर पुनरावृति करना चाहिए, और प्रत्येक पुनरावृत्ति के दौरान कंसोल पर एक संदेश प्रदर्शित करना चाहिए Pet
। आइए ऐसी विधि लिखने का प्रयास करें: Cat
Dog
public static void iterateAnimals(Collection<Animal> animals) {
for(Animal animal: animals) {
System.out.println("Another iteration in the loop!");
}
}
ऐसा लगता है कि समस्या हल हो गई है! हालाँकि, जैसा कि हमने हाल ही में सीखा है, List<Cat>
और List<Dog>
! List<Pet>
के वंशज नहीं हैं List<Animal>
! इसका मतलब यह है कि जब हम iterateAnimals()
बिल्लियों की सूची के साथ विधि को कॉल करने का प्रयास करते हैं, तो हमें एक संकलन त्रुटि मिलती है:
import java.util.*;
public class Main3 {
public static void iterateAnimals(Collection<Animal> animals) {
for(Animal animal: animals) {
System.out.println("Another iteration in the loop!");
}
}
public static void main(String[] args) {
List<Cat> cats = new ArrayList<>();
cats.add(new Cat());
cats.add(new Cat());
cats.add(new Cat());
cats.add(new Cat());
// Compilation error!
iterateAnimals(cats);
}
}
स्थिति हमारे लिए बहुत अच्छी नहीं दिख रही है! क्या हमें प्रत्येक प्रकार के जानवरों की गणना करने के लिए अलग-अलग तरीके लिखने होंगे? वास्तव में, नहीं, हम नहीं :) और जैसा कि होता है, वाइल्डकार्ड इसमें हमारी मदद करते हैं! हम निम्नलिखित निर्माण का उपयोग करके एक सरल विधि से समस्या को हल कर सकते हैं:
public static void iterateAnimals(Collection<? extends Animal> animals) {
for(Animal animal: animals) {
System.out.println("Another iteration in the loop!");
}
}
यह एक वाइल्डकार्ड है। अधिक सटीक रूप से, यह कई प्रकार के वाइल्डकार्ड्स में से पहला है। इसे अपर-बाउंड वाइल्डकार्ड के रूप में जाना जाता है और इसके द्वारा व्यक्त किया जाता है ? विस्तार करता है । यह रचना हमें क्या बताती है? इसका मतलब यह है कि विधि Animal
वस्तुओं के संग्रह या किसी भी वर्ग की वस्तुओं के संग्रह को स्वीकार करती है जो Animal
(? जानवरों को फैलाती है) से उतरती है। दूसरे शब्दों में, विधि Animal
, Pet
, Dog
, या Cat
वस्तुओं के संग्रह को स्वीकार कर सकती है - इससे कोई फर्क नहीं पड़ता। आइए खुद को विश्वास दिलाएं कि यह काम करता है:
public static void main(String[] args) {
List<Animal> animals = new ArrayList<>();
animals.add(new Animal());
animals.add(new Animal());
List<Pet> pets = new ArrayList<>();
pets.add(new Pet());
pets.add(new Pet());
List<Cat> cats = new ArrayList<>();
cats.add(new Cat());
cats.add(new Cat());
List<Dog> dogs = new ArrayList<>();
dogs.add(new Dog());
dogs.add(new Dog());
iterateAnimals(animals);
iterateAnimals(pets);
iterateAnimals(cats);
iterateAnimals(dogs);
}
कंसोल आउटपुट:
Another iteration in the loop!
Another iteration in the loop!
Another iteration in the loop!
Another iteration in the loop!
Another iteration in the loop!
Another iteration in the loop!
Another iteration in the loop!
Another iteration in the loop!
हमने कुल 4 संग्रह और 8 ऑब्जेक्ट बनाए, और कंसोल पर ठीक 8 प्रविष्टियाँ हैं। सब कुछ बढ़िया काम करता है! :) वाइल्डकार्ड ने हमें विशिष्ट प्रकार से बंधे आवश्यक तर्क को एक विधि में आसानी से फिट करने की अनुमति दी। हमने प्रत्येक प्रकार के जानवर के लिए एक अलग विधि लिखने की आवश्यकता को समाप्त कर दिया। कल्पना कीजिए कि अगर हमारे आवेदन का उपयोग चिड़ियाघर या पशु चिकित्सा कार्यालय द्वारा किया जाता तो हमें कितने तरीकों की आवश्यकता होती :) Animal
, Pet
नीचे की कक्षा के साथ, और अगले स्तर पर Cat
और कक्षाएं। Dog
अब आपको iterateAnimals()
विधि को फिर से लिखने की आवश्यकता है ताकि कुत्तों को छोड़कर किसी भी प्रकार के जानवरों के साथ काम किया जा सके । यानी इसे स्वीकार करना चाहिए Collection<Animal>
,Collection<Pet>
या Collection<Car>
, लेकिन इसके साथ काम नहीं करना चाहिए Collection<Dog>
। हम इसे कैसे प्राप्त कर सकते हैं? ऐसा लगता है कि हम फिर से प्रत्येक प्रकार के लिए एक अलग विधि लिखने की संभावना का सामना करते हैं:/हम संकलक को और कैसे समझाते हैं कि हम क्या करना चाहते हैं? यह वास्तव में काफी सरल है! एक बार फिर, वाइल्डकार्ड यहां हमारी सहायता के लिए आते हैं। लेकिन इस बार हम एक अन्य प्रकार के वाइल्डकार्ड का उपयोग करेंगे - एक निचली सीमा वाला वाइल्डकार्ड , जिसे सुपर का उपयोग करके व्यक्त किया जाता है ।
public static void iterateAnimals(Collection<? super Cat> animals) {
for(int i = 0; i < animals.size(); i++) {
System.out.println("Another iteration in the loop!");
}
}
यहाँ सिद्धांत समान है। निर्माण <? super Cat>
संकलक को बताता है कि iterateAnimals()
विधि इनपुट के रूप में वस्तुओं के संग्रह Cat
या Cat
वर्ग के किसी पूर्वज को इनपुट के रूप में स्वीकार कर सकती है। इस मामले में, Cat
वर्ग, उसके माता-पिता Pet
, और उसके माता-पिता के माता-पिता, Animal
सभी इस विवरण से मेल खाते हैं। वर्ग Dog
हमारे प्रतिबंध से मेल नहीं खाता है, इसलिए तर्क के साथ विधि का उपयोग करने का प्रयास List<Dog>
एक संकलन त्रुटि का परिणाम देगा:
public static void main(String[] args) {
List<Animal> animals = new ArrayList<>();
animals.add(new Animal());
animals.add(new Animal());
List<Pet> pets = new ArrayList<>();
pets.add(new Pet());
pets.add(new Pet());
List<Cat> cats = new ArrayList<>();
cats.add(new Cat());
cats.add(new Cat());
List<Dog> dogs = new ArrayList<>();
dogs.add(new Dog());
dogs.add(new Dog());
iterateAnimals(animals);
iterateAnimals(pets);
iterateAnimals(cats);
// Compilation error!
iterateAnimals(dogs);
}
हमने अपनी समस्या हल कर ली है, और एक बार फिर वाइल्डकार्ड अत्यंत उपयोगी साबित हुए :) इसके साथ, पाठ समाप्त हो गया है। अब आप देख सकते हैं कि जावा के आपके अध्ययन में जेनरिक कितने महत्वपूर्ण हैं - हमारे पास उनके बारे में 4 संपूर्ण पाठ हैं! लेकिन अब आप इस विषय में अच्छी तरह से वाकिफ हैं और आप नौकरी के साक्षात्कार में अपने कौशल को साबित कर सकते हैं :) और अब, कार्यों पर वापस जाने का समय आ गया है! आपकी पढ़ाई में सबसे अच्छी सफलता! :)
GO TO FULL VERSION