हाय! चला जेनेरिकचा अभ्यास सुरू ठेवूया. मागील धड्यांमधून ( जेनेरिक्ससह काम करताना वॅरग्स वापरण्याबद्दल आणि इरेजरच्या प्रकाराबद्दल ) तुम्हाला त्यांच्याबद्दलचे बरेच ज्ञान आधीच मिळाले आहे , परंतु एक महत्त्वाचा विषय आहे ज्याचा आम्ही अद्याप विचार केलेला नाही — वाइल्डकार्ड्स . हे जेनेरिकचे अतिशय महत्त्वाचे वैशिष्ट्य आहे. इतकं की आम्ही त्यासाठी वेगळा धडा समर्पित केला आहे! ते म्हणाले, वाइल्डकार्ड्समध्ये विशेषत: क्लिष्ट काहीही नाही. तुम्हाला ते लगेच दिसेल :) चला एक उदाहरण पाहू:
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
. येथे कोणतीही समस्या नाही - सर्वकाही अपेक्षेप्रमाणे कार्य करते. परंतु दुसऱ्या स्थितीत, कंपाइलर त्रुटी निर्माण करतो. पण आपण तेच करत आहोत, नाही का? यावेळी आपण फक्त अनेक वस्तूंचा संग्रह वापरत आहोत. पण त्रुटी का उद्भवते? फरक काय आहे? String
आपण एक ऑब्जेक्ट एका Object
किंवा 20 वस्तूंवर टाकत आहोत ? वस्तू आणि वस्तूंचा संग्रह यांच्यात महत्त्वाचा फरक आहे . जर 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