जेनरिक और टाइप-इरेज़र


10

जावा में जेनरिक को इरेज़र प्रकार के उपयोग से लागू किया जाता है। जेएलएस का कहना है कि प्रेरणा पिछड़ी अनुकूलता थी। जहाँ दूसरी ओर C # जेनेरिक रिफ़ायरेबल हैं।

सैद्धांतिक रूप से जेनरिक को "इरेज़र" या "रिफ़िरेबल" होने के क्या फायदे और नुकसान हैं?

क्या जावा कुछ याद कर रहा है?

जवाबों:


8

खैर, प्रेरणा (पीछे की संगतता) एक फायदा और नुकसान दोनों है। यह नुकसान की बात है क्योंकि हम सभी को पुन: प्रयोज्य प्रकार देना पसंद करेंगे, लेकिन भुगतान करने की कीमत अधिक थी। सी # में डिजाइन विकल्पों पर विचार करें। उनके पास पुन: प्रयोज्य प्रकार हैं, लेकिन अब उनके पास डुप्लिकेट एपीआई हैं। तो, एक जावा एपीआई की कल्पना करें जहां हमारे पास हर पैरामीटर वाले वर्ग के लिए डुप्लिकेट एपीआई भी थे। अब, अपने आप को विरासत की कक्षाओं से नई जेनेरिक कक्षाओं तक कोड की हजारों लाइनों को चित्रित करें। अब, डुप्लिकेट एपीआई को एक नुकसान नहीं माना जाएगा? लेकिन हे, वे reifiable प्रकार है!

तो, प्रमुख प्रेरणा "विकासवाद थी, न कि क्रांति"। और तार्किक रूप से, हर फैसले में ट्रेडऑफ होता है।

उल्लिखित अन्य नुकसानों के अलावा, हम इस तथ्य को भी जोड़ सकते हैं कि संकलन के समय संकलन के बारे में तर्क करना मुश्किल हो सकता है, क्योंकि यह स्पष्ट नहीं है कि कुछ प्रकार हटा दिए जाएंगे, और यह त्रुटियों को खोजने के लिए बहुत ही अजीब और कठिन होता है।

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

प्रमुख नुकसान पहले से ही स्पष्ट तथ्य से निकलते हैं कि सामान्य प्रकारों के लिए एक ही वर्ग और एकाधिक वर्ग नहीं हैं। जैसा कि एक अन्य उदाहरण पर विचार करें कि एक ही सामान्य वर्ग के साथ एक विधि को ओवरलोड करना जावा में विफल रहता है:

public void doSomething(List<One>);
public void doSomething(List<Two>);

ऐसा कुछ जिसे पुन: प्रयोज्य प्रकारों के नुकसान के रूप में देखा जा सकता है (कम से कम C # में) यह तथ्य है कि वे कोड विस्फोट का कारण बनते हैं । उदाहरण के लिए List<int>एक वर्ग है, और एक List<double>और पूरी तरह से अलग है, क्योंकि यह एक List<string>और एक है List<MyType>। इसलिए कक्षाओं को रनटाइम पर परिभाषित किया जाना चाहिए, जिससे कक्षाओं का विस्फोट हो सकता है और उत्पन्न होने पर मूल्यवान संसाधनों का उपभोग किया जा सकता है।

इस तथ्य के बारे में कि new T()जावा में एक को परिभाषित करना संभव नहीं है , एक अन्य उत्तर में उल्लेख किया गया है, यह विचार करना भी दिलचस्प है कि यह केवल प्रकार के क्षरण का मामला नहीं है। इसके लिए एक डिफ़ॉल्ट निर्माणकर्ता के अस्तित्व की भी आवश्यकता होती है, यही कारण है कि C # को इसके लिए एक "नए अवरोध" की आवश्यकता होती है। (देखें कि एलेक्स बकले द्वारा जावा में नया टी () क्यों संभव नहीं है )।


3
मुझे लगता है कि मैं यह कहने में सही हूं कि सीएलआर पर, संदर्भ प्रकार T एस के लिए, आपको Class<T>सभी Tएस के लिए कोड की केवल एक प्रति मिलती है ; प्लस प्रत्येक मूल्य प्रकार के लिए एक अतिरिक्त प्रतिलिपि Tवास्तव में उपयोग किया जाता है।
आकाश

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

6

प्रकार के क्षरण का नकारात्मक पक्ष यह है कि आप रनटाइम के सामान्य प्रकार के बारे में नहीं जानते हैं। इसका मतलब यह है कि आप उन पर प्रतिबिंब लागू नहीं कर सकते हैं और आप उन्हें रनटाइम पर नहीं रोक सकते हैं।

आप जावा में ऐसा कुछ नहीं कर सकते:

public class MyClass<T> {
    private T t;

    //more methods    
    public void myMethod() {
        //more code
        if (someCondition) {
            t = new T();//illegal
        } else {
            T[] array = new T[];//illegal
        }            
    }       
}

इसके लिए वर्कअराउंड है लेकिन इसके लिए अधिक कोड की आवश्यकता होती है। लाभ, जैसा कि आपने इसका उल्लेख किया है, पश्चगामी संगतता है।


3

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

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

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



मिटाए गए जेनरिक के पक्ष में एक और कारण यह है कि निर्भरता को इस तरह से इंजेक्ट किया जाना चाहिए जो अभिव्यक्ति की समस्या के समाधान का सम्मान करता है। यदि आप प्रकारों के विशिष्ट मामलों के लिए परीक्षण कर रहे हैं या अपने जेनेरिक फ़ंक्शन में किसी कारखाने को हार्डकोडिंग कर रहे हैं, तो आप एक्स्टेंसिबिलिटी को गलत कर रहे हैं।
शेल्बी मूर III
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.