जावा में जेनेरिक

जेनरिक सामान्य प्रोग्रामिंग की एक सुविधा है जिसे 2004 में जावा प्लेटफ़ॉर्म, मानक संस्करण 5.0 के भीतर जावा (प्रोग्रामिंग भाषा) में जोड़ा गया था। उन्हें संकलन-समय प्रकार की सुरक्षा प्रदान करते हुए विभिन्न प्रकार की वस्तुओं पर एक प्रकार या विधि को संचालित करने की अनुमति देने के लिए जावा के प्रकार प्रणाली का विस्तार करने के लिए डिज़ाइन किया गया था। पहलू संकलन-समय प्रकार की सुरक्षा पूरी तरह से हासिल नहीं की गई थी, क्योंकि 2016 में यह दिखाया गया था कि सभी मामलों में इसकी गारंटी नहीं है।

जावा संग्रह ढाँचा संग्रह उदाहरण में संग्रहीत वस्तुओं के प्रकार को निर्दिष्ट करने के लिए जेनेरिक का समर्थन करता है।

1998 में, गिलाद ब्राचा, मार्टिन ओडर्सकी, डेविड स्टाउटमायर और फिलिप वाडलर ने जेनेरिक जावा बनाया, जो सामान्य प्रकारों का समर्थन करने के लिए जावा भाषा का एक विस्तार था। जेनेरिक जावा को वाइल्डकार्ड (जावा) के साथ जावा में शामिल किया गया था।

पदानुक्रम और वर्गीकरण
जावा भाषा विशिष्टता के अनुसार:
 * एक प्रकार का चर एक अयोग्य पहचानकर्ता है। प्रकार चर ्स को जेनेरिक क्लास डिक्लेरेशन, जेनेरिक इंटरफ़ेस डिक्लेरेशन, जेनेरिक मेथड डिक्लेरेशन और जेनेरिक कंस्ट्रक्टर डिक्लेरेशन द्वारा पेश किया जाता है।
 * एक वर्ग सामान्य है यदि वह एक या अधिक प्रकार के चर घोषित करता है। यह एक या अधिक प्रकार के वेरिएबल को परिभाषित करता है जो पैरामीटर के रूप में कार्य करते हैं। एक सामान्य वर्ग घोषणा पैरामीटरयुक्त प्रकारों के एक सेट को परिभाषित करती है, जो प्रकार पैरामीटर अनुभाग के प्रत्येक संभावित आह्वान के लिए एक है। ये सभी पैरामीटरयुक्त प्रकार रनटाइम पर एक ही क्लास साझा करते हैं।
 * एक इंटरफ़ेस (जावा) सामान्य है यदि यह एक या अधिक प्रकार के चर घोषित करता है। यह एक या अधिक प्रकार के वेरिएबल को परिभाषित करता है जो पैरामीटर के रूप में कार्य करते हैं। एक सामान्य इंटरफ़ेस घोषणा प्रकार के एक सेट को परिभाषित करती है, प्रकार पैरामीटर अनुभाग के प्रत्येक संभावित आह्वान के लिए एक। सभी पैरामीटरयुक्त प्रकार रनटाइम पर समान इंटरफ़ेस साझा करते हैं।
 * एक विधि सामान्य है यदि यह एक या अधिक प्रकार के चर घोषित करती है। इस प्रकार के चर को विधि के औपचारिक प्रकार के पैरामीटर के रूप में जाना जाता है। औपचारिक प्रकार पैरामीटर सूची का रूप किसी वर्ग या इंटरफ़ेस के प्रकार पैरामीटर सूची के समान है।
 * एक कंस्ट्रक्टर को जेनेरिक घोषित किया जा सकता है, चाहे कंस्ट्रक्टर को जिस वर्ग में घोषित किया गया है वह स्वयं जेनेरिक है या नहीं। एक कंस्ट्रक्टर सामान्य होता है यदि वह एक या अधिक प्रकार के वेरिएबल घोषित करता है। इन प्रकार के चर को कंस्ट्रक्टर के औपचारिक प्रकार के पैरामीटर के रूप में जाना जाता है। औपचारिक प्रकार पैरामीटर सूची का रूप सामान्य वर्ग या इंटरफ़ेस की प्रकार पैरामीटर सूची के समान है।

प्रेरणा
जावा कोड का निम्नलिखित ब्लॉक उस समस्या को दर्शाता है जो जेनेरिक का उपयोग न करने पर मौजूद होती है। सबसे पहले, यह एक घोषणा करता है प्रकार का. फिर, यह एक जोड़ता है  तक. अंत में, यह जोड़े गए को पुनः प्राप्त करने का प्रयास करता है  और इसे एक पर डालें  -तर्क में एक त्रुटि, क्योंकि आम तौर पर एक पूर्णांक में एक मनमाना स्ट्रिंग डालना संभव नहीं है।

हालाँकि कोड बिना किसी त्रुटि के संकलित किया गया है, यह एक रनटाइम अपवाद फेंकता है कोड की तीसरी पंक्ति निष्पादित करते समय। जेनरिक का उपयोग करके संकलन समय के दौरान इस प्रकार की तर्क त्रुटि का पता लगाया जा सकता है और उनका उपयोग करने के लिए प्राथमिक प्रेरणा है। यह एक या अधिक प्रकार के वेरिएबल को परिभाषित करता है जो पैरामीटर के रूप में कार्य करते हैं।

उपरोक्त कोड खंड को जेनेरिक का उपयोग करके निम्नानुसार फिर से लिखा जा सकता है:

प्रकार पैरामीटर  कोण कोष्ठक के भीतर घोषित करता है   का गठन किया जाना है   (का एक वंशज  सामान्य है   घटक)। जेनेरिक के साथ, तीसरी पंक्ति को किसी विशेष प्रकार में डालना अब आवश्यक नहीं है, क्योंकि इसका परिणाम   परिभाषित किया जाता है   कंपाइलर द्वारा उत्पन्न कोड द्वारा.

इस खंड की तीसरी पंक्ति में तार्किक दोष को संकलन समय|संकलन-समय त्रुटि (J2SE 5.0 या बाद के संस्करण के साथ) के रूप में पता लगाया जाएगा क्योंकि संकलक इसका पता लगाएगा  रिटर्न   के बजाय. अधिक विस्तृत उदाहरण के लिए, संदर्भ देखें। यहां इंटरफ़ेस की परिभाषा का एक छोटा सा अंश दिया गया है और पैकेज में:

सामान्य वर्ग परिभाषाएँ
यहां एक सामान्य जावा क्लास का उदाहरण दिया गया है, जिसका उपयोग मानचित्र (कंप्यूटर विज्ञान) में व्यक्तिगत प्रविष्टियों (वैल्यू मैपिंग की कुंजी) को दर्शाने के लिए किया जा सकता है:

इस सामान्य वर्ग का उपयोग निम्नलिखित तरीकों से किया जा सकता है, उदाहरण के लिए:

यह आउटपुट देता है:  ग्रेड: (माइक, ए) निशान: (माइक, 100) 13 अभाज्य है. 

सामान्य विधि परिभाषाएँ
उपरोक्त सामान्य वर्ग का उपयोग करते हुए एक सामान्य विधि का उदाहरण यहां दिया गया है: नोट: यदि हम पहले को हटा दें  उपरोक्त विधि में, हमें संकलन त्रुटि मिलेगी (प्रतीक प्रकार नहीं मिल सका), क्योंकि यह प्रतीक की घोषणा का प्रतिनिधित्व करता है।

कई मामलों में, विधि के उपयोगकर्ता को प्रकार के मापदंडों को इंगित करने की आवश्यकता नहीं होती है, क्योंकि उनका अनुमान लगाया जा सकता है:

यदि आवश्यक हो तो पैरामीटर स्पष्ट रूप से जोड़े जा सकते हैं:

आदिम प्रकारों के उपयोग की अनुमति नहीं है, और इसके बजाय ऑब्जेक्ट प्रकार (ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग)#बॉक्सिंग संस्करणों का उपयोग किया जाना चाहिए:

दिए गए मापदंडों के आधार पर सामान्य तरीके बनाने की भी संभावना है।

ऐसे मामलों में आप आदिम प्रकारों का भी उपयोग नहीं कर सकते, उदाहरण के लिए:

डायमंड ऑपरेटर
प्रकार अनुमान के लिए धन्यवाद, जावा एसई 7 और इसके बाद के संस्करण प्रोग्रामर को कोण कोष्ठक की एक खाली जोड़ी को प्रतिस्थापित करने की अनुमति देते हैं (, जिसे डायमंड ऑपरेटर कहा जाता है) कोण कोष्ठक की एक जोड़ी के लिए जिसमें एक या अधिक प्रकार के पैरामीटर होते हैं जो पर्याप्त रूप से बंद संदर्भ प्रकार रूपांतरण # अंतर्निहित प्रकार रूपांतरण करते हैं। इस प्रकार, उपरोक्त कोड उदाहरण का उपयोग करना  इस प्रकार पुनः लिखा जा सकता है:

वाइल्डकार्ड टाइप करें
पैरामीटरयुक्त प्रकार के लिए एक प्रकार का तर्क किसी ठोस वर्ग या इंटरफ़ेस तक सीमित नहीं है। जावा पैरामीटरयुक्त प्रकारों के लिए प्रकार के तर्क के रूप में टाइप वाइल्डकार्ड के उपयोग की अनुमति देता है। वाइल्डकार्ड प्रपत्र में प्रकार के तर्क हैं ; वैकल्पिक रूप से ऊपरी या निचले सीमाबद्ध परिमाणीकरण के साथ। यह देखते हुए कि वाइल्डकार्ड द्वारा दर्शाया गया सटीक प्रकार अज्ञात है, उन तरीकों के प्रकार पर प्रतिबंध लगाए जाते हैं जिन्हें किसी ऑब्जेक्ट पर बुलाया जा सकता है जो पैरामीटरयुक्त प्रकारों का उपयोग करता है।

यहां एक उदाहरण दिया गया है जहां तत्व प्रकार a  वाइल्डकार्ड द्वारा पैरामीटराइज़ किया गया है:

चूँकि हम नहीं जानते कि तत्व किस प्रकार का है  का अर्थ है, हम इसमें ऑब्जेक्ट नहीं जोड़ सकते।   e> विधि प्रकार के तर्क लेती है , का तत्व प्रकार   सामान्य इंटरफ़ेस. जब वास्तविक प्रकार का तर्क है, यह किसी अज्ञात प्रकार का प्रतीक है। हम किसी भी विधि तर्क मान को पास करते हैं   विधि को इस अज्ञात प्रकार का एक उपप्रकार होना होगा। चूँकि हम नहीं जानते कि वह किस प्रकार का है, हम कुछ भी पास नहीं कर सकते। एकमात्र अपवाद शून्य सूचक है; जो हर प्रकार का सदस्य है. किसी प्रकार के वाइल्डकार्ड की सीमाबद्ध मात्रा निर्दिष्ट करने के लिए, कीवर्ड का उपयोग यह इंगित करने के लिए किया जाता है कि प्रकार तर्क बाउंडिंग क्लास का एक उपप्रकार है। इसलिए  का अर्थ है कि दी गई सूची में कुछ अज्ञात प्रकार की वस्तुएं शामिल हैं जो इसका विस्तार करती हैं   कक्षा। उदाहरण के लिए, सूची हो सकती है   या. सूची से किसी तत्व को पढ़ने पर एक परिणाम प्राप्त होगा. फिर से, अशक्त तत्वों को जोड़ने की भी अनुमति है। उपरोक्त वाइल्डकार्ड का उपयोग लचीलापन जोड़ता है चूंकि प्रकार के तर्क के रूप में ठोस प्रकार के साथ किन्हीं दो पैरामीटरयुक्त प्रकारों के बीच कोई वंशानुक्रम संबंध नहीं है। कोई भी नहीं  और न   दूसरे का एक उपप्रकार है; चाहे   का एक उपप्रकार है. तो, कोई भी तरीका जो अपनाता है  एक पैरामीटर के रूप में किसी तर्क को स्वीकार नहीं करता है. यदि ऐसा होता, तो इसे सम्मिलित करना संभव होता  वह एक नहीं है   यह में; जो प्रकार की सुरक्षा का उल्लंघन करता है। यहां एक उदाहरण दिया गया है जो दर्शाता है कि यदि किस प्रकार की सुरक्षा का उल्लंघन किया जाएगा   का एक उपप्रकार थे  :

वाइल्डकार्ड के साथ समाधान काम करता है क्योंकि यह उन परिचालनों की अनुमति नहीं देता है जो प्रकार की सुरक्षा का उल्लंघन करेंगे:

किसी प्रकार के वाइल्डकार्ड के निचले बाउंडिंग वर्ग को निर्दिष्ट करने के लिए,  कीवर्ड का प्रयोग किया जाता है. यह कीवर्ड इंगित करता है कि प्रकार तर्क बाउंडिंग क्लास का एक सुपरटाइप है। इसलिए, प्रतिनिधित्व कर सकता है   या. परिभाषित सूची से पढ़ना प्रकार के तत्व लौटाता है. ऐसी सूची में जोड़ने के लिए या तो प्रकार के तत्वों की आवश्यकता होती है, का कोई भी उपप्रकार   या शून्य सूचक (जो हर प्रकार का सदस्य है)।

जोशुआ बलोच की पुस्तक इफेक्टिव जावा से स्मरणीय पीईसीएस (निर्माता एक्सटेंड्स, कंज्यूमर सुपर) यह याद रखने का एक आसान तरीका देता है कि जावा में वाइल्डकार्ड (Covariance_and_contravariance_(computer_science) और Covariance और contravariance (कंप्यूटर विज्ञान) के अनुरूप) का उपयोग कब करना है।

थ्रो क्लॉज़ में जेनरिक
हालाँकि अपवाद स्वयं सामान्य नहीं हो सकते, सामान्य पैरामीटर थ्रो क्लॉज में दिखाई दे सकते हैं:

प्रकार मिटाने की समस्या
टाइप-शुद्धता के लिए संकलन-समय पर जेनेरिक की जाँच की जाती है। सामान्य प्रकार की जानकारी को प्रकार मिटाना नामक प्रक्रिया में हटा दिया जाता है। उदाहरण के लिए,  गैर-जेनेरिक प्रकार में परिवर्तित कर दिया जाएगा , जिसमें आम तौर पर मनमानी वस्तुएं शामिल होती हैं। संकलन-समय जांच यह गारंटी देती है कि परिणामी कोड सही प्रकार का उपयोग करता है।

प्रकार मिटाने के कारण, रन-टाइम पर प्रकार पैरामीटर निर्धारित नहीं किए जा सकते। उदाहरण के लिए, जब ए  रनटाइम पर जांच की जाती है, यह निर्धारित करने का कोई सामान्य तरीका नहीं है कि, प्रकार मिटाने से पहले, यह एक था   या एक. कई लोग इस प्रतिबंध से असंतुष्ट हैं. आंशिक दृष्टिकोण हैं. उदाहरण के लिए, व्यक्तिगत तत्वों की जांच यह निर्धारित करने के लिए की जा सकती है कि वे किस प्रकार के हैं; उदाहरण के लिए, यदि कोई  एक शामिल है , कि ArrayList को पैरामीटरयुक्त किया गया होगा   (हालाँकि, इसे किसी भी माता-पिता के साथ पैरामीटराइज़ किया गया हो सकता है  , जैसे कि   या  ).

इस बिंदु को प्रदर्शित करते हुए, निम्नलिखित कोड समान आउटपुट देता है: प्रकार के क्षरण का एक अन्य प्रभाव यह है कि एक सामान्य वर्ग इसका विस्तार नहीं कर सकता है  कक्षा किसी भी तरह से, प्रत्यक्ष या अप्रत्यक्ष रूप से:

इसके समर्थित न होने का कारण प्रकार का क्षरण है: टाइप इरेज़र के कारण, रनटाइम को पता नहीं चलेगा कि कौन सा कैच ब्लॉक निष्पादित करना है, इसलिए यह कंपाइलर द्वारा निषिद्ध है।

जावा जेनेरिक सी++ टेम्पलेट्स|C++ टेम्प्लेट से भिन्न हैं। उपयोग किए गए पैरामीटर प्रकारों की संख्या की परवाह किए बिना, जावा जेनेरिक एक जेनेरिक वर्ग या फ़ंक्शन का केवल एक संकलित संस्करण उत्पन्न करते हैं। इसके अलावा, जावा रन-टाइम वातावरण को यह जानने की आवश्यकता नहीं है कि किस पैरामीटरयुक्त प्रकार का उपयोग किया जाता है क्योंकि प्रकार की जानकारी संकलन-समय पर मान्य होती है और संकलित कोड में शामिल नहीं होती है। नतीजतन, एक पैरामीटरयुक्त प्रकार के जावा क्लास को इंस्टेंट करना असंभव है क्योंकि इंस्टेंटेशन के लिए एक कंस्ट्रक्टर को कॉल की आवश्यकता होती है, जो कि प्रकार अज्ञात होने पर अनुपलब्ध है।

उदाहरण के लिए, निम्नलिखित कोड संकलित नहीं किया जा सकता: चूँकि रनटाइम पर प्रति जेनेरिक क्लास की केवल एक प्रतिलिपि होती है, स्थैतिक चर को क्लास के सभी उदाहरणों के बीच साझा किया जाता है, चाहे उनके प्रकार के पैरामीटर कुछ भी हों। नतीजतन, प्रकार पैरामीटर का उपयोग स्थिर चर की घोषणा में या स्थिर तरीकों में नहीं किया जा सकता है।

जावा SE5 से पहले लिखे गए प्रोग्रामों के साथ बैकवर्ड संगतता बनाए रखने के लिए जावा में टाइप इरेज़र लागू किया गया था।

सरणी से अंतर
सरणियों (आदिम सरणियों और दोनों) के बीच कई महत्वपूर्ण अंतर हैं Object सरणियाँ), और जावा में जेनेरिक। दो प्रमुख अंतर, वेरिएंस (कंप्यूटर विज्ञान) और रीफिकेशन (कंप्यूटर विज्ञान) के संदर्भ में अंतर।

सहप्रसरण, प्रतिप्रसरण और अपरिवर्तन
जेनेरिक अपरिवर्तनीय हैं, जबकि सरणियाँ सहप्रसरण और प्रतिप्रसरण (कंप्यूटर विज्ञान) हैं। सरणियों जैसी गैर-जेनेरिक वस्तुओं की तुलना में जेनेरिक का उपयोग करने का यह एक लाभ है। विशेष रूप से, जेनरिक डेवलपर को कोड को ठीक करने के लिए मजबूर करने के लिए एक संकलन-समय अपवाद फेंककर रन टाइम अपवादों को रोकने में मदद कर सकता है।

उदाहरण के लिए, यदि कोई डेवलपर घोषित करता है Object[] ऑब्जेक्ट और ऑब्जेक्ट को नए के रूप में त्वरित करता है Long[] ऑब्जेक्ट, कोई संकलन-समय अपवाद नहीं फेंका गया है (चूंकि सरणियाँ सहसंयोजक हैं)। इससे यह ग़लत धारणा बन सकती है कि कोड सही ढंग से लिखा गया है। हालाँकि, यदि डेवलपर a जोड़ने का प्रयास करता है String इसके लिये Long[]ऑब्जेक्ट, प्रोग्राम फेंक देगा ArrayStoreException. यदि डेवलपर जेनेरिक का उपयोग करता है तो इस रन-टाइम अपवाद से पूरी तरह बचा जा सकता है।

यदि डेवलपर घोषित करता है a Collection ऑब्जेक्ट रिटर्न प्रकार के साथ इस ऑब्जेक्ट का एक नया उदाहरण बनाता है ArrayList, जावा कंपाइलर (सही ढंग से) असंगत प्रकारों की उपस्थिति को इंगित करने के लिए एक संकलन-समय अपवाद फेंक देगा (क्योंकि जेनेरिक अपरिवर्तनीय हैं)।. इसलिए, यह संभावित रन-टाइम अपवादों से बचा जाता है। का एक उदाहरण बनाकर इस समस्या को ठीक किया जा सकता है Collection का उपयोग करना ArrayList इसके बजाय ऑब्जेक्ट करें। जावा SE7 या बाद के संस्करणों का उपयोग करने वाले कोड के लिए, Collection को एक के साथ त्वरित किया जा सकता है ArrayList<> Java#Diamond_operator में जेनेरिक्स का उपयोग करके ऑब्जेक्ट

पुनःकरण
Arrays Reification (कंप्यूटर विज्ञान) है, जिसका अर्थ है कि एक Array ऑब्जेक्ट रन-टाइम पर अपने प्रकार की जानकारी को लागू करता है, जबकि Java में जेनरिक को Reified नहीं किया जाता है।

अधिक औपचारिक रूप से कहें तो, जावा में सामान्य प्रकार वाली वस्तुएं गैर-शोधन योग्य प्रकार हैं। एक गैर-शोधन योग्य प्रकार वह प्रकार है जिसका रन-टाइम पर प्रतिनिधित्व में संकलन-समय पर इसके प्रतिनिधित्व की तुलना में कम जानकारी होती है।

जावा में सामान्य प्रकार वाली वस्तुएं प्रकार के क्षरण के कारण पुन:शोधन योग्य नहीं होती हैं। जावा केवल संकलन-समय पर प्रकार की जानकारी लागू करता है। संकलन-समय पर प्रकार की जानकारी सत्यापित होने के बाद, प्रकार की जानकारी हटा दी जाती है, और रन-टाइम पर, प्रकार की जानकारी उपलब्ध नहीं होगी।

गैर-शोधन योग्य प्रकारों के उदाहरणों में शामिल हैं List और List, कहाँ T एक सामान्य औपचारिक पैरामीटर है।

जेनेरिक पर प्रोजेक्ट
प्रोजेक्ट वल्लाह (जावा भाषा) जावा 10 से आगे के संभावित संस्करणों के लिए बेहतर जावा जेनेरिक और भाषा सुविधाओं को विकसित करने के लिए एक प्रायोगिक परियोजना है। संभावित संवर्द्धन में शामिल हैं:
 * सामान्य प्रोग्रामिंग#टेम्पलेट विशेषज्ञता, उदा. सूची
 * सी शार्प और जावा#टाइप इरेज़र बनाम रिफाइड जेनेरिक की तुलना; रनटाइम पर वास्तविक प्रकार उपलब्ध कराना।

यह भी देखें

 * सामान्य प्रोग्रामिंग
 * टेम्प्लेट मेटाप्रोग्रामिंग
 * वाइल्डकार्ड (जावा)
 * सी शार्प और जावा की तुलना|सी# और जावा की तुलना
 * जावा और सी++ की तुलना

संदर्भ


<!--