வணக்கம்! இன்றைய பாடத்தில், ஜெனரிக்ஸைத் தொடர்ந்து படிப்போம். இது நடக்கும் போது, இது ஒரு பெரிய தலைப்பு, ஆனால் அதைத் தவிர்க்க முடியாது - இது மொழியின் மிக முக்கியமான பகுதியாகும் :) நீங்கள் ஆரக்கிள் ஆவணங்களைப் படிக்கும் போது அல்லது ஆன்லைன் டுடோரியல்களைப் படிக்கும்போது, மறுசீரமைக்க முடியாத வகைகள் மற்றும் மறுசீரமைப்பு வகைகள் . மறுபரிசீலனை செய்யக்கூடிய வகை என்பது இயக்க நேரத்தில் தகவல் முழுமையாகக் கிடைக்கும் வகையாகும். ஜாவாவில், இத்தகைய வகைகளில் பழமையான வகைகள், மூல வகைகள் மற்றும் பொதுவானவை அல்லாத வகைகள் ஆகியவை அடங்கும். இதற்கு நேர்மாறாக, மறுசீரமைக்க முடியாத வகைகள், அவற்றின் தகவல்கள் அழிக்கப்பட்டு, இயக்க நேரத்தில் அணுக முடியாத வகைகளாகும். நடப்பதால், இவை பொதுவானவை -
குவியல் மாசுபாடு பின்வரும் சூழ்நிலைகளில் ஏற்படலாம்:
List<String>
, List<Integer>
, போன்றவை.
மூலம், varargs என்றால் என்ன என்று உங்களுக்கு நினைவிருக்கிறதா?
நீங்கள் மறந்துவிட்டால், இது ஒரு மாறி-நீள வாதமாகும். எங்கள் முறைக்கு எத்தனை வாதங்கள் அனுப்பப்படலாம் என்று எங்களுக்குத் தெரியாத சூழ்நிலைகளில் அவை பயனுள்ளதாக இருக்கும். எடுத்துக்காட்டாக, எங்களிடம் ஒரு கால்குலேட்டர் வகுப்பு இருந்தால், அது ஒருsum
முறையைக் கொண்டுள்ளது. முறை sum()
2 எண்கள், அல்லது 3, அல்லது 5, அல்லது நீங்கள் விரும்பும் பலவற்றைப் பெறலாம். sum()
சாத்தியமான ஒவ்வொரு வாதங்களுக்கும் முறையை ஓவர்லோட் செய்வது மிகவும் விசித்திரமாக இருக்கும் . அதற்கு பதிலாக, நாம் இதைச் செய்யலாம்:
public class SimpleCalculator {
public static int sum(int...numbers) {
int result = 0;
for(int i : numbers) {
result += i;
}
return result;
}
public static void main(String[] args) {
System.out.println(sum(1,2,3,4,5));
System.out.println(sum(2,9));
}
}
கன்சோல் வெளியீடு:
15
11
ஜெனரிக்ஸுடன் இணைந்து varargs ஐப் பயன்படுத்தும் போது சில முக்கியமான அம்சங்கள் இருப்பதை இது காட்டுகிறது. பின்வரும் குறியீட்டைப் பார்ப்போம்:
import javafx.util.Pair;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static <E> void addAll(List<E> list, E... array) {
for (E element : array) {
list.add(element);
}
}
public static void main(String[] args) {
addAll(new ArrayList<String>(), // This is okay
"Leonardo da Vinci",
"Vasco de Gama"
);
// but here we get a warning
addAll(new ArrayList<Pair<String, String>>(),
new Pair<String, String>("Leonardo", "da Vinci"),
new Pair<String, String>("Vasco", "de Gama")
);
}
}
இந்த முறை உள்ளீடு a மற்றும் பல பொருள்களை addAll()
எடுத்துக்கொள்கிறது , பின்னர் அது இந்த அனைத்து பொருட்களையும் பட்டியலில் சேர்க்கிறது. முறையில் , நாங்கள் எங்கள் முறையை இரண்டு முறை அழைக்கிறோம். முதல் வழக்கில், நாம் இரண்டு சாதாரண சரங்களை சேர்க்கிறோம் . இங்கே எல்லாம் ஒழுங்காக உள்ளது. இரண்டாவது வழக்கில், நாம் இரண்டு பொருட்களை சேர்க்கிறோம் . ஆனால் இங்கே நாம் எதிர்பாராத விதமாக ஒரு எச்சரிக்கையைப் பெறுகிறோம்: List<E>
E
main()
addAll()
List
Pair<String, String>
List
Unchecked generics array creation for varargs parameter
அதற்கு என்ன பொருள்? நாம் ஏன் ஒரு எச்சரிக்கையைப் பெறுகிறோம், ஏன் ஒரு குறிப்பு உள்ளது array
? எல்லாவற்றிற்கும் மேலாக, எங்கள் குறியீட்டில் ஒரு இல்லை array
! இரண்டாவது வழக்கிலிருந்து ஆரம்பிக்கலாம். கம்பைலர் மாறி-நீள வாதத்தை (varargs) வரிசையாக மாற்றுவதால் எச்சரிக்கை ஒரு வரிசையைக் குறிப்பிடுகிறது. வேறு வார்த்தைகளில் கூறுவதானால், எங்கள் addAll()
முறையின் கையொப்பம்:
public static <E> void addAll(List<E> list, E... array)
உண்மையில் இது போல் தெரிகிறது:
public static <E> void addAll(List<E> list, E[] array)
அதாவது, இந்த முறையில் main()
, கம்பைலர் நமது குறியீட்டை இவ்வாறு மாற்றுகிறது:
public static void main(String[] args) {
addAll(new ArrayList<String>(),
new String[] {
"Leonardo da Vinci",
"Vasco de Gama"
}
);
addAll(new ArrayList<Pair<String,String>>(),
new Pair<String,String>[] {
new Pair<String,String>("Leonardo","da Vinci"),
new Pair<String,String>("Vasco","de Gama")
}
);
}
ஒரு String
வரிசை நன்றாக உள்ளது. ஆனால் ஒரு Pair<String, String>
வரிசை இல்லை. சிக்கல் என்னவென்றால், அது Pair<String, String>
மறுசீரமைக்க முடியாத வகையாகும். தொகுப்பின் போது, வகை வாதங்கள் (<ஸ்ட்ரிங், சரம்>) பற்றிய அனைத்து தகவல்களும் அழிக்கப்படும். மறுசீரமைக்க முடியாத வகையின் வரிசைகளை உருவாக்குவது ஜாவாவில் அனுமதிக்கப்படாது . நீங்கள் ஒரு ஜோடி<ஸ்ட்ரிங், ஸ்ட்ரிங்> வரிசையை கைமுறையாக உருவாக்க முயற்சித்தால் இதைக் காணலாம்
public static void main(String[] args) {
// Compilation error Generic array creation
Pair<String, String>[] array = new Pair<String, String>[10];
}
காரணம் வெளிப்படையானது: வகை பாதுகாப்பு. நீங்கள் நினைவுகூருவது போல், ஒரு வரிசையை உருவாக்கும் போது, எந்த பொருட்களை (அல்லது primitives) வரிசை சேமிக்கும் என்பதை நீங்கள் கண்டிப்பாக குறிப்பிட வேண்டும்.
int array[] = new int[10];
எங்களின் முந்தைய பாடங்களில் ஒன்றில், அழித்தல் வகையை விரிவாக ஆராய்ந்தோம். Pair
இந்த வழக்கில், வகை அழித்தல் பொருள்கள் ஜோடிகளை சேமிக்கும் தகவலை இழக்கச் செய்கிறது <String, String>
. வரிசையை உருவாக்குவது பாதுகாப்பற்றதாக இருக்கும். varargs மற்றும் generics ஆகியவற்றை உள்ளடக்கிய முறைகளைப் பயன்படுத்தும் போது , வகை அழித்தல் மற்றும் அது எவ்வாறு செயல்படுகிறது என்பதைப் பற்றி நினைவில் வைத்துக் கொள்ளுங்கள். நீங்கள் எழுதிய குறியீட்டைப் பற்றி நீங்கள் உறுதியாக இருந்தால், அது எந்தச் சிக்கலையும் ஏற்படுத்தாது என்று தெரிந்தால், சிறுகுறிப்புகளைப் பயன்படுத்தி varargs தொடர்பான எச்சரிக்கைகளை முடக்கலாம் . @SafeVarargs
@SafeVarargs
public static <E> void addAll(List<E> list, E... array) {
for (E element : array) {
list.add(element);
}
}
இந்த சிறுகுறிப்பை உங்கள் முறையில் சேர்த்தால், நாங்கள் முன்பு சந்தித்த எச்சரிக்கை தோன்றாது. ஜெனரிக்ஸுடன் varargs ஐப் பயன்படுத்தும் போது ஏற்படக்கூடிய மற்றொரு பிரச்சனை குவியல் மாசுபாடு ஆகும். 
import java.util.ArrayList;
import java.util.List;
public class Main {
static List<String> polluteHeap() {
List numbers = new ArrayList<Number>();
numbers.add(1);
List<String> strings = numbers;
strings.add("");
return strings;
}
public static void main(String[] args) {
List<String> stringsWithHeapPollution = polluteHeap();
System.out.println(stringsWithHeapPollution.get(0));
}
}
கன்சோல் வெளியீடு:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
எளிமையான சொற்களில், குவியல் மாசுபாடு என்பது வகைப் பொருள்கள் A
குவியலாக இருக்க வேண்டும், ஆனால் B
வகைப் பாதுகாப்பு தொடர்பான பிழைகள் காரணமாக வகைப் பொருள்கள் அங்கேயே முடிவடையும். எங்கள் எடுத்துக்காட்டில், இது துல்லியமாக நடக்கிறது. முதலில், நாங்கள் மூல மாறியை உருவாக்கி , அதற்கு numbers
ஒரு பொதுவான சேகரிப்பை ( ) ஒதுக்கினோம் . பின்னர் சேகரிப்பில் ArrayList<Number>
எண்ணைச் சேர்த்தோம் .1
List<String> strings = numbers;
இந்த வரியில், கம்பைலர் " தேர்வு செய்யப்படாத அசைன்மென்ட்... " எச்சரிக்கையை வழங்குவதன் மூலம் சாத்தியமான பிழைகள் குறித்து எச்சரிக்க முயன்றது , ஆனால் நாங்கள் அதை புறக்கணித்தோம். List<String>
வகையின் பொதுவான தொகுப்பை சுட்டிக்காட்டும் வகையின் பொதுவான மாறியுடன் முடிவடைகிறோம் ArrayList<Number>
. தெளிவாக, இந்த நிலைமை சிக்கலுக்கு வழிவகுக்கும்! அதனால் அது செய்கிறது. எங்கள் புதிய மாறியைப் பயன்படுத்தி, சேகரிப்பில் ஒரு சரத்தைச் சேர்க்கிறோம். எங்களிடம் இப்போது குவியல் மாசு உள்ளது - அளவுருப்படுத்தப்பட்ட சேகரிப்பில் ஒரு எண்ணைச் சேர்த்துள்ளோம், பின்னர் ஒரு சரத்தையும் சேர்த்துள்ளோம். கம்பைலர் எங்களை எச்சரித்தார், ஆனால் அதன் எச்சரிக்கையை நாங்கள் புறக்கணித்தோம். இதன் விளைவாக, ClassCastException
நிரல் இயங்கும் போது மட்டுமே நமக்கு கிடைக்கும். இதற்கும் varargs க்கும் என்ன சம்பந்தம்? ஜெனரிக்ஸுடன் varargs ஐப் பயன்படுத்துவது எளிதில் குவியல் மாசுபாட்டிற்கு வழிவகுக்கும். இங்கே ஒரு எளிய உதாரணம்:
import java.util.Arrays;
import java.util.List;
public class Main {
static void polluteHeap(List<String>... stringsLists) {
Object[] array = stringsLists;
List<Integer> numbersList = Arrays.asList(66,22,44,12);
array[0] = numbersList;
String str = stringsLists[0].get(0);
}
public static void main(String[] args) {
List<String> cars1 = Arrays.asList("Ford", "Fiat", "Kia");
List<String> cars2 = Arrays.asList("Ferrari", "Bugatti", "Zaporozhets");
polluteHeap(cars1, cars2);
}
}
இங்கே என்ன நடந்து கொண்டிருக்கின்றது? வகை அழிப்பு காரணமாக, எங்கள் மாறி-நீள வாதம்
List<String>...stringsLists
பட்டியல்களின் வரிசையாக மாறும், அதாவது List[]
, தெரியாத வகை பொருள்கள் (தொகுப்பின் போது varargs வழக்கமான வரிசையாக மாறும் என்பதை மறந்துவிடாதீர்கள்). இதன் காரணமாக, முறையின் முதல் வரியில் உள்ள மாறிக்கு அதை எளிதாக ஒதுக்கலாம் Object[] array
- எங்கள் பட்டியலில் உள்ள பொருட்களின் வகை அழிக்கப்பட்டது! இப்போது நம்மிடம் ஒரு Object[]
மாறி உள்ளது, ஜாவாவில் உள்ள அனைத்து பொருட்களும் மரபுரிமையாக இருப்பதால், அதில் எதையும் சேர்க்கலாம் Object
! முதலில், எங்களிடம் சரங்களின் பட்டியல்கள் மட்டுமே உள்ளன. ஆனால் அழித்தல் மற்றும் varargs ஐப் பயன்படுத்துவதன் மூலம், நாம் செய்யும் எண்களின் பட்டியலை எளிதாகச் சேர்க்கலாம். இதன் விளைவாக, பல்வேறு வகையான பொருட்களைக் கலந்து குவியல்களை மாசுபடுத்துகிறோம். ClassCastException
வரிசையிலிருந்து ஒரு சரத்தைப் படிக்க முயலும்போது முடிவு மற்றொருதாக இருக்கும் . கன்சோல் வெளியீடு:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
varargs என்ற எளிய பொறிமுறையைப் பயன்படுத்துவதன் மூலம் இதுபோன்ற எதிர்பாராத விளைவுகள் ஏற்படலாம் :) அதனுடன், இன்றைய பாடம் முடிவுக்கு வருகிறது. ஓரிரு பணிகளைத் தீர்க்க மறக்காதீர்கள், உங்களுக்கு நேரமும் ஆற்றலும் இருந்தால், சில கூடுதல் வாசிப்பைப் படிக்கவும். " பயனுள்ள ஜாவா " தன்னைப் படிக்காது! :) அடுத்த முறை வரை!
GO TO FULL VERSION