வணக்கம்! ஜெனரிக்ஸ் பற்றிய எங்கள் தொடர் பாடங்களை நாங்கள் தொடர்கிறோம். அவை என்ன, அவை ஏன் தேவைப்படுகின்றன என்பதற்கான பொதுவான யோசனையை நாங்கள் முன்பு பெற்றோம். இன்று நாம் ஜெனரிக்ஸின் சில அம்சங்களைப் பற்றியும் அவற்றுடன் பணிபுரிவது பற்றியும் மேலும் அறிந்து கொள்வோம். போகலாம்! சென்ற பாடத்தில்
ஜெனரிக் வகைகளுக்கும் , ரா வகைகளுக்கும் உள்ள வித்தியாசத்தைப் பற்றிப் பேசினோம் . மூல வகை என்பது ஒரு பொதுவான வகுப்பாகும், அதன் வகை அகற்றப்பட்டது.
ஆவணம் கூறுகிறது, "டி - இந்த கிளாஸ் ஆப்ஜெக்ட்டால் வடிவமைக்கப்பட்ட வகுப்பின் வகை." இதை ஆவண மொழியிலிருந்து எளிய பேச்சுக்கு மொழிபெயர்த்தால், பொருளின் வர்க்கம்

List list = new ArrayList();
இதோ ஒரு உதாரணம். எங்களில் எந்த வகையான பொருள்கள் வைக்கப்படும் என்பதை இங்கே குறிப்பிடவில்லை List
. அத்தகைய ஒன்றை உருவாக்கி அதில் சில பொருட்களைச் சேர்க்க முயற்சித்தால் List
, ஐடியாவில் ஒரு எச்சரிக்கையைக் காண்போம்:
"Unchecked call to add(E) as a member of raw type of java.util.List".
ஆனால் ஜாவா 5 இல் மட்டுமே ஜெனரிக்ஸ் தோன்றியதைப் பற்றியும் பேசினோம். இந்த பதிப்பு வெளியிடப்பட்ட நேரத்தில், புரோகிராமர்கள் ஏற்கனவே மூல வகைகளைப் பயன்படுத்தி ஒரு கொத்து குறியீட்டை எழுதியுள்ளனர், எனவே மொழியின் இந்த அம்சம் செயல்படுவதை நிறுத்த முடியவில்லை, மேலும் திறன் ஜாவாவில் மூல வகைகளை உருவாக்குவது பாதுகாக்கப்பட்டது. இருப்பினும், பிரச்சனை மிகவும் பரவலாக மாறியது. உங்களுக்குத் தெரியும், ஜாவா குறியீடு பைட்கோட் எனப்படும் சிறப்பு தொகுக்கப்பட்ட வடிவமாக மாற்றப்படுகிறது, பின்னர் அது ஜாவா மெய்நிகர் இயந்திரத்தால் செயல்படுத்தப்படுகிறது. ஆனால் மாற்றும் செயல்பாட்டின் போது வகை அளவுருக்கள் பற்றிய தகவலை பைட்கோடில் வைத்தால், அது முன்னர் எழுதப்பட்ட அனைத்து குறியீடுகளையும் உடைத்துவிடும், ஏனெனில் ஜாவா 5 க்கு முன் வகை அளவுருக்கள் எதுவும் இல்லை! ஜெனரிக்ஸுடன் பணிபுரியும் போது, நீங்கள் நினைவில் கொள்ள வேண்டிய ஒரு மிக முக்கியமான கருத்து உள்ளது. இது வகை அழிப்பு என்று அழைக்கப்படுகிறது. ஒரு வகுப்பில் வகை அளவுரு பற்றிய எந்தத் தகவலும் இல்லை என்று அர்த்தம். இந்தத் தகவல் தொகுப்பின் போது மட்டுமே கிடைக்கும் மற்றும் இயக்க நேரத்திற்கு முன் அழிக்கப்படும் (அணுக முடியாததாக மாறும்). உங்கள் இல் தவறான வகை பொருளை வைக்க முயற்சித்தால் List<String>
, கம்பைலர் பிழையை உருவாக்கும். மொழியின் படைப்பாளிகள் பொதுவானவற்றை உருவாக்கும்போது இதைத்தான் அடைய விரும்புகிறார்கள்: தொகுக்கும் நேரச் சரிபார்ப்புகள். ஆனால் உங்கள் ஜாவா குறியீடு அனைத்தும் பைட்கோடாக மாறும்போது, அதில் வகை அளவுருக்கள் பற்றிய தகவல்கள் இருக்காது. பைட்கோடில், உங்கள் பூனைகளின் பட்டியல் சரங்களை List<Cat>
விட வேறுபட்டதல்ல . List<String>
பைட்கோடில், பொருள்களின் cats
பட்டியல் என்று எதுவும் கூறவில்லை Cat
. தொகுப்பின் போது அத்தகைய தகவல்கள் அழிக்கப்படும் - உங்களிடம் ஒரு பட்டியல் உள்ளது என்ற உண்மை மட்டுமே List<Object> cats
நிரலின் பைட்கோடில் முடிவடையும். இது எவ்வாறு செயல்படுகிறது என்பதைப் பார்ப்போம்:
public class TestClass<T> {
private T value1;
private T value2;
public void printValues() {
System.out.println(value1);
System.out.println(value2);
}
public static <T> TestClass<T> createAndAdd2Values(Object o1, Object o2) {
TestClass<T> result = new TestClass<>();
result.value1 = (T) o1;
result.value2 = (T) o2;
return result;
}
public static void main(String[] args) {
Double d = 22.111;
String s = "Test String";
TestClass<Integer> test = createAndAdd2Values(d, s);
test.printValues();
}
}
நாங்கள் எங்கள் சொந்த பொதுவான TestClass
வகுப்பை உருவாக்கினோம். இது மிகவும் எளிமையானது: இது உண்மையில் 2 பொருள்களின் ஒரு சிறிய "சேகரிப்பு" ஆகும், அவை பொருள் உருவாக்கப்பட்டவுடன் உடனடியாக சேமிக்கப்படும். T
இது 2 புலங்களைக் கொண்டுள்ளது . முறை செயல்படுத்தப்படும் போது createAndAdd2Values()
, இரண்டு அனுப்பப்பட்ட பொருள்கள் ( Object a
மற்றும் வகைக்கு அனுப்பப்பட்டு பின்னர் பொருளுடன் சேர்க்கப்பட Object b
வேண்டும் . முறையில் , நாம் ஒரு உருவாக்குகிறோம் , அதாவது வகை வாதம் வகை அளவுருவை மாற்றுகிறது . நாங்கள் a மற்றும் a to ஐயும் கடந்து செல்கிறோம். எங்கள் நிரல் வேலை செய்யும் என்று நீங்கள் நினைக்கிறீர்களா? எல்லாவற்றிற்கும் மேலாக, நாங்கள் வகை வாதம் என்று குறிப்பிட்டோம், ஆனால் நிச்சயமாக ஒரு க்கு அனுப்ப முடியாது !T
TestClass
main()
TestClass<Integer>
Integer
Integer
Double
String
createAndAdd2Values()
Integer
String
Integer
main()
முறை மற்றும் சரிபார்ப்பு. கன்சோல் வெளியீடு:
22.111
Test String
அது எதிர்பாராதது! இது ஏன் நடந்தது? இது வகை அழிப்பின் விளைவு. குறியீடு தொகுக்கப்படும் போது, Integer
நமது பொருளை உடனுக்குடன் வழங்கப் பயன்படுத்தப்படும் வகை வாதம் பற்றிய தகவல் அழிக்கப்பட்டது. TestClass<Integer> test
களம் ஆகிறது TestClass<Object> test
. எங்களுடைய Double
மற்றும் String
வாதங்கள் எளிதில் பொருள்களாக மாற்றப்பட்டன Object
(நாம் எதிர்பார்த்தபடி அவை பொருள்களாக மாற்றப்படவில்லை Integer
!) மற்றும் அமைதியாக சேர்க்கப்பட்டது TestClass
. இங்கே மற்றொரு எளிய ஆனால் மிகவும் வெளிப்படுத்தும் வகை அழித்தல் உதாரணம்:
import java.util.ArrayList;
import java.util.List;
public class Main {
private class Cat {
}
public static void main(String[] args) {
List<String> strings = new ArrayList<>();
List<Integer> numbers = new ArrayList<>();
List<Cat> cats = new ArrayList<>();
System.out.println(strings.getClass() == numbers.getClass());
System.out.println(numbers.getClass() == cats.getClass());
}
}
கன்சோல் வெளியீடு:
true
true
நாங்கள் மூன்று வெவ்வேறு வகையான வாதங்களுடன் சேகரிப்புகளை உருவாக்கியுள்ளோம் - String
, Integer
, மற்றும் எங்கள் சொந்த Cat
வகுப்பு. ஆனால் பைட்கோடாக மாற்றும் போது, மூன்று பட்டியல்களும் ஆகின்றன List<Object>
, எனவே நிரல் இயங்கும் போது அது மூன்று நிகழ்வுகளிலும் ஒரே வகுப்பைப் பயன்படுத்துகிறோம் என்று சொல்கிறது.
வரிசைகள் மற்றும் ஜெனரிக்ஸுடன் பணிபுரியும் போது அழிப்பதைத் தட்டச்சு செய்யவும்
வரிசைகள் மற்றும் பொதுவான வகுப்புகளுடன் (அதாவது) பணிபுரியும் போது தெளிவாக புரிந்து கொள்ள வேண்டிய மிக முக்கியமான விஷயம் உள்ளதுList
. உங்கள் நிரலுக்கான தரவு கட்டமைப்புகளைத் தேர்ந்தெடுக்கும்போது அதைக் கருத்தில் கொள்ள வேண்டும். ஜெனரிக்ஸ் வகை அழிப்புக்கு உட்பட்டது. இயக்க நேரத்தில் வகை அளவுருக்கள் பற்றிய தகவல் கிடைக்கவில்லை. இதற்கு நேர்மாறாக, வரிசைகள் நிரல் இயங்கும் போது அவற்றின் தரவு வகையைப் பற்றி அறிந்திருக்கும் மற்றும் அவற்றைப் பயன்படுத்தலாம். தவறான வகையை அணிவரிசையில் வைக்க முயற்சிப்பது விதிவிலக்கு அளிக்கப்படும்:
public class Main2 {
public static void main(String[] args) {
Object x[] = new String[3];
x[0] = new Integer(222);
}
}
கன்சோல் வெளியீடு:
Exception in thread "main" java.lang.ArrayStoreException: java.lang.Integer
வரிசைகள் மற்றும் ஜெனரிக்ஸ் இடையே பெரிய வித்தியாசம் இருப்பதால், அவை பொருந்தக்கூடிய சிக்கல்களைக் கொண்டிருக்கலாம். எல்லாவற்றிற்கும் மேலாக, நீங்கள் பொதுவான பொருள்களின் வரிசையையோ அல்லது ஒரு அளவுரு வரிசையையோ உருவாக்க முடியாது. கொஞ்சம் குழப்பமாக இருக்கிறதா? பார்க்கலாம். எடுத்துக்காட்டாக, ஜாவாவில் நீங்கள் எதையும் செய்ய முடியாது:
new List<T>[]
new List<String>[]
new T[]
நாம் பொருள்களின் வரிசையை உருவாக்க முயற்சித்தால் List<String>
, பொதுவான வரிசை உருவாக்கத்தைப் பற்றி புகார் செய்யும் தொகுத்தல் பிழையைப் பெறுவோம்:
import java.util.List;
public class Main2 {
public static void main(String[] args) {
// Compilation error! Generic array creation
List<String>[] stringLists = new List<String>[1];
}
}
ஆனால் இது ஏன் செய்யப்படுகிறது? அத்தகைய வரிசைகளை உருவாக்குவது ஏன் அனுமதிக்கப்படவில்லை? இவை அனைத்தும் வகை பாதுகாப்பை வழங்குவதற்காக. கம்பைலர் இதுபோன்ற பொதுவான பொருள்களின் வரிசைகளை உருவாக்க அனுமதித்தால், நமக்கு நாமே ஒரு டன் சிக்கல்களை உருவாக்கலாம். ஜோசுவா ப்ளாச்சின் "எஃபெக்டிவ் ஜாவா" புத்தகத்திலிருந்து ஒரு எளிய உதாரணம் இங்கே:
public static void main(String[] args) {
List<String>[] stringLists = new List<String>[1]; // (1)
List<Integer> intList = Arrays.asList(42, 65, 44); // (2)
Object[] objects = stringLists; // (3)
objects[0] = intList; // (4)
String s = stringLists[0].get(0); // (5)
}
ஒரு வரிசையை உருவாக்குவது List<String>[] stringLists
அனுமதிக்கப்படுகிறது மற்றும் தொகுத்தல் பிழையை உருவாக்காது என்று கற்பனை செய்யலாம். இது உண்மையாக இருந்தால், நாம் செய்யக்கூடிய சில விஷயங்கள் இங்கே உள்ளன: வரி 1 இல், பட்டியல்களின் வரிசையை உருவாக்குகிறோம்: List<String>[] stringLists
. எங்கள் வரிசையில் ஒன்று உள்ளது List<String>
. வரி 2 இல், எண்களின் பட்டியலை உருவாக்குகிறோம்: List<Integer>
. வரி 3 இல், நாம் List<String>[]
ஒரு Object[] objects
மாறிக்கு ஒதுக்குகிறோம். ஜாவா மொழி இதை அனுமதிக்கிறது: பொருள்களின் வரிசை அனைத்து துணைப்பிரிவுகளின் பொருள்களையும் பொருட்களையும் X
சேமிக்க முடியும் . அதன்படி, நீங்கள் எதையும் ஒரு வரிசையில் வைக்கலாம் . வரி 4 இல், வரிசையின் (a ) ஒரே உறுப்பை a உடன் மாற்றுவோம் . இவ்வாறு, சேமித்து வைப்பதற்காக மட்டுமே ஒரு வரிசையில் வைக்கிறோம்X
X
Object
objects()
List<String>
List<Integer>
List<Integer>
List<String>
பொருள்கள்! வரி 5 ஐ இயக்கும் போது மட்டுமே பிழையை சந்திப்போம். A ClassCastException
இயக்க நேரத்தில் எறியப்படும். அதன்படி, அத்தகைய வரிசைகளை உருவாக்குவதற்கான தடை ஜாவாவில் சேர்க்கப்பட்டது. இது போன்ற சூழ்நிலைகளை தவிர்க்கலாம்.
அழித்தல் வகையை நான் எவ்வாறு சுற்றி வர முடியும்?
சரி, வகை அழித்தல் பற்றி அறிந்தோம். கணினியை ஏமாற்ற முயற்சிப்போம்! :) பணி: எங்களிடம் பொதுவானTestClass<T>
வகுப்பு உள்ளது. createNewT()
இந்த வகுப்பிற்கு ஒரு புதிய பொருளை உருவாக்கி திருப்பி அனுப்பும் முறையை எழுத விரும்புகிறோம் T
. ஆனால் இது சாத்தியமற்றது, இல்லையா? தொகுப்பின் போது வகை பற்றிய அனைத்து தகவல்களும் T
அழிக்கப்படும், மேலும் இயக்க நேரத்தில் நாம் எந்த வகையான பொருளை உருவாக்க வேண்டும் என்பதை தீர்மானிக்க முடியாது. இதைச் செய்ய உண்மையில் ஒரு தந்திரமான வழி உள்ளது. ஜாவாவுக்கு ஒரு வகுப்பு இருப்பது உங்களுக்கு நினைவிருக்கலாம் Class
. எங்களின் எந்தவொரு பொருளின் வகுப்பையும் தீர்மானிக்க இதைப் பயன்படுத்தலாம்:
public class Main2 {
public static void main(String[] args) {
Class classInt = Integer.class;
Class classString = String.class;
System.out.println(classInt);
System.out.println(classString);
}
}
கன்சோல் வெளியீடு:
class java.lang.Integer
class java.lang.String
ஆனால் இங்கே நாம் பேசாத ஒரு அம்சம் உள்ளது. ஆரக்கிள் ஆவணத்தில், வகுப்பு வகுப்பு பொதுவானது என்பதை நீங்கள் காண்பீர்கள்! 
https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html
Integer.class
வெறும் அல்ல Class
, மாறாக Class<Integer>
. பொருளின் வகை String.class
வெறும் Class
, மாறாக Class<String>
, போன்றவை. இன்னும் தெளிவாக இல்லை என்றால், முந்தைய எடுத்துக்காட்டில் வகை அளவுருவைச் சேர்க்க முயற்சிக்கவும்:
public class Main2 {
public static void main(String[] args) {
Class<Integer> classInt = Integer.class;
// Compilation error!
Class<String> classInt2 = Integer.class;
Class<String> classString = String.class;
// Compilation error!
Class<Double> classString2 = String.class;
}
}
இப்போது, இந்த அறிவைப் பயன்படுத்தி, வகை அழிப்பைத் தவிர்த்து, எங்கள் பணியைச் செய்யலாம்! வகை அளவுருவைப் பற்றிய தகவலைப் பெற முயற்சிப்போம். எங்கள் வகை வாதம் இருக்கும் MySecretClass
:
public class MySecretClass {
public MySecretClass() {
System.out.println("A MySecretClass object was created successfully!");
}
}
நடைமுறையில் எங்கள் தீர்வை எவ்வாறு பயன்படுத்துகிறோம் என்பது இங்கே:
public class TestClass<T> {
Class<T> typeParameterClass;
public TestClass(Class<T> typeParameterClass) {
this.typeParameterClass = typeParameterClass;
}
public T createNewT() throws IllegalAccessException, InstantiationException {
T t = typeParameterClass.newInstance();
return t;
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
TestClass<MySecretClass> testString = new TestClass<>(MySecretClass.class);
MySecretClass secret = testString.createNewT();
}
}
கன்சோல் வெளியீடு:
A MySecretClass object was created successfully!
எங்கள் பொதுவான வகுப்பின் கட்டமைப்பாளருக்கு தேவையான வகுப்பு வாதத்தை நாங்கள் அனுப்பியுள்ளோம்:
TestClass<MySecretClass> testString = new TestClass<>(MySecretClass.class);
இது வகை வாதத்தைப் பற்றிய தகவலைச் சேமிக்க அனுமதித்தது, அது முற்றிலும் அழிக்கப்படுவதைத் தடுக்கிறது. இதன் விளைவாக, எங்களால் உருவாக்க முடிந்ததுT
பொருள்! :) இத்துடன் இன்றைய பாடம் முடிவடைகிறது. ஜெனரிக்ஸுடன் பணிபுரியும் போது, நீங்கள் எப்போதும் அழிப்பு வகையை நினைவில் கொள்ள வேண்டும். இந்த தீர்வு மிகவும் வசதியானதாகத் தெரியவில்லை, ஆனால் ஜெனரிக்ஸ் உருவாக்கப்பட்ட போது ஜாவா மொழியின் பகுதியாக இல்லை என்பதை நீங்கள் புரிந்து கொள்ள வேண்டும். அளவுருக் கொண்ட சேகரிப்புகளை உருவாக்கவும், தொகுக்கும்போது பிழைகளைப் பிடிக்கவும் உதவும் இந்த அம்சம், பின்னர் கையாளப்பட்டது. முதல் பதிப்பிலிருந்து பொதுவானவற்றை உள்ளடக்கிய வேறு சில மொழிகளில், எந்த வகை அழிப்பும் இல்லை (உதாரணமாக, C# இல்). சொல்லப்போனால், நாங்கள் ஜெனரிக்ஸ் படித்து முடிக்கவில்லை! அடுத்த பாடத்தில், ஜெனரிக்ஸின் மேலும் சில அம்சங்களைப் பற்றி நீங்கள் அறிந்து கொள்வீர்கள். இப்போதைக்கு ஒன்றிரண்டு பணிகளைத் தீர்ப்பது நல்லது! :)
GO TO FULL VERSION