नमस्ते! आज के पाठ में, हम जेनरिक का अध्ययन करना जारी रखेंगे। जैसा कि होता है, यह एक बड़ा विषय है, लेकिन इससे कोई परहेज नहीं है - यह भाषा का एक अत्यंत महत्वपूर्ण हिस्सा है :) जब आप जेनरिक पर Oracle दस्तावेज़ का अध्ययन करते हैं या ऑनलाइन ट्यूटोरियल पढ़ते हैं, तो आप गैर-पुनर्स्थापना योग्य शब्दों के पार आएंगे और पुन: प्रयोज्य प्रकार । एक पुन: प्रयोज्य प्रकार एक प्रकार है जिसके लिए जानकारी रनटाइम पर पूरी तरह से उपलब्ध होती है। जावा में, ऐसे प्रकारों में आदिम, कच्चे प्रकार और गैर-सामान्य प्रकार शामिल हैं। इसके विपरीत, गैर-पुनर्स्थापना योग्य प्रकार वे प्रकार होते हैं जिनकी जानकारी मिटा दी जाती है और रनटाइम पर पहुंच योग्य नहीं होती है। जैसा कि होता है, ये जेनरिक हैं —
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")
);
}
}
विधि 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>
एक गैर-पुन: प्रयोज्य प्रकार है। संकलन के दौरान, प्रकार के तर्कों (<स्ट्रिंग, स्ट्रिंग>) के बारे में सभी जानकारी मिटा दी जाती है। जावा में एक गैर-पुन: प्रयोज्य प्रकार के सरणियों के निर्माण की अनुमति नहीं है । यदि आप मैन्युअल रूप से Pair<String, String> सरणी बनाने का प्रयास करते हैं तो आप इसे देख सकते हैं
public static void main(String[] args) {
// Compilation error Generic array creation
Pair<String, String>[] array = new Pair<String, String>[10];
}
कारण स्पष्ट है: टाइप सुरक्षा। जैसा कि आपको याद होगा, एक सरणी बनाते समय, आपको निश्चित रूप से यह निर्दिष्ट करने की आवश्यकता होती है कि सरणी कौन सी वस्तुओं (या आदिम) को संग्रहीत करेगी।
int array[] = new int[10];
हमारे पिछले पाठों में से एक में, हमने विस्तार से टाइप इरेज़र की जाँच की। इस मामले में, टाइप इरेज़र हमें उन सूचनाओं को खोने का कारण बनता है जो ऑब्जेक्ट जोड़े को Pair
स्टोर करते हैं । <String, String>
सरणी बनाना असुरक्षित होगा। varargs और जेनरिक को शामिल करने वाली विधियों का उपयोग करते समय , टाइप इरेज़र और यह कैसे काम करता है, के बारे में याद रखना सुनिश्चित करें। यदि आप अपने द्वारा लिखे गए कोड के बारे में पूरी तरह से निश्चित हैं और जानते हैं कि इससे कोई समस्या नहीं होगी, तो आप एनोटेशन का उपयोग करके varargs से संबंधित चेतावनियों को बंद कर सकते हैं । @SafeVarargs
@SafeVarargs
public static <E> void addAll(List<E> list, E... array) {
for (E element : array) {
list.add(element);
}
}
यदि आप इस एनोटेशन को अपनी विधि में जोड़ते हैं, तो हमें पहले जो चेतावनी मिली थी, वह दिखाई नहीं देगी। जेनरिक के साथ वैरग का उपयोग करते समय उत्पन्न होने वाली एक अन्य समस्या हीप प्रदूषण है। हीप प्रदूषण निम्न स्थितियों में हो सकता है:
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 का उपयोग करने से ढेर प्रदूषण आसानी से हो सकता है। यहाँ एक सरल उदाहरण है:
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