வணக்கம்! ஜெனரிக்ஸ் பற்றிய நமது படிப்பைத் தொடரலாம். முந்தைய பாடங்களில் இருந்து நீங்கள் ஏற்கனவே கணிசமான அறிவைப் பெற்றுள்ளீர்கள் ( பொதுவானது மற்றும் வகை அழிப்பைப் பற்றி வேலை செய்யும் போது 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
பொருளுக்கு அனுப்புகிறோம். இங்கே எந்த பிரச்சனையும் இல்லை - எல்லாம் எதிர்பார்த்தபடி செயல்படும். ஆனால் இரண்டாவது சூழ்நிலையில், கம்பைலர் ஒரு பிழையை உருவாக்குகிறது. ஆனால் நாங்கள் அதையே செய்கிறோம், இல்லையா? இந்த நேரத்தில் நாங்கள் பல பொருட்களின் தொகுப்பைப் பயன்படுத்துகிறோம். ஆனால் பிழை ஏன் ஏற்படுகிறது? என்ன வித்தியாசம்? 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