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

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

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

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

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

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

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

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

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

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

यहां पैकेज में इंटरफेस  और  की परिभाषा से छोटा सा अंश दिया गया है:

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

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

यह आउटपुट देता है:

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

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

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

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

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

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

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

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

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

चूँकि हम नहीं जानते कि तत्व टाइप  का क्या अर्थ है, हम इसमें ऑब्जेक्ट नहीं जोड़ सकते।   विधि   e> टाइप के लॉजिक लेती है, जो कि   जेनेरिक इंटरफ़ेस का तत्व टाइप है। जब वास्तविक टाइप का लॉजिक   होता है, तो यह किसी अज्ञात टाइप का प्रतिनिधित्व करता है।   विधि में हम जो भी विधि लॉजिक मान पास करते हैं वह इस अज्ञात टाइप का उपटाइप होना चाहिए। चूँकि हम नहीं जानते कि वह किस टाइप का है, हम कुछ भी पारित नहीं कर सकते हैं। एकमात्र अपवाद शून्य है; जो हर टाइप का सदस्य है।

किसी टाइप के वाइल्डकार्ड की ऊपरी सीमा को निर्दिष्ट करने के लिए, कीवर्ड का उपयोग यह इंगित करने के लिए किया जाता है कि टाइप लॉजिक बाउंडिंग क्लास का उपटाइप है। तो  का अर्थ है कि दी गई लिस्ट में कुछ अज्ञात टाइप की वस्तुएं हैं जो   वर्ग का विस्तार करती हैं। उदाहरण के लिए, लिस्ट   या   हो सकती है। लिस्ट से किसी तत्व को पढ़ने पर   वापस आ जाएगी। फिर से, अशक्त तत्वों को जोड़ने की भी अनुमति है।

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

पुनःकरण
ऐरे को पुनरीक्षित किया जाता है, जिसका अर्थ है कि ऐरे ऑब्जेक्ट रन-टाइम पर अपने टाइप की जानकारी को प्रयुक्त करता है, जबकि जावा में जेनेरिक को पुन: संशोधित नहीं किया जाता है।

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

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

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

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

यह भी देखें

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