2009-06-24 19 views
27

यह बॉक्सिंग और अनबॉक्सिंग के बारे में कोई सवाल नहीं है, यह है क्यों जावा और सी # जैसी भाषाओं की आवश्यकता है?कुछ भाषाओं को बॉक्सिंग और अनबॉक्सिंग की आवश्यकता क्यों है?

मैं सी ++, एसटीएल और बूस्ट से काफी परिचित हूं।

C++ में मैं कुछ इस तरह बहुत आसानी से लिख सकता है,

std::vector<double> dummy; 

मैं जावा के साथ कुछ अनुभव है, लेकिन मैं क्योंकि मैं कुछ इस तरह लिखना पड़ा वास्तव में हैरान था,

ArrayList<Double> dummy = new ArrayList<Double>(); 

मेरा सवाल, यह एक वस्तु क्यों होनी चाहिए, जेनेरिक के बारे में बात करते समय आदिम प्रकारों को शामिल करने के लिए तकनीकी रूप से इतना कठिन क्या है?

+0

सी ++ से जावा तक आ रहा है, जब मैं इस तथ्य की खोज करता हूं तो मैं पूरी तरह से बेहद चौंक गया था ... – GuLearn

उत्तर

46

जेनरिक के बारे में बात करते समय आदिम प्रकारों को शामिल करने के लिए तकनीकी रूप से इतना कठिन क्या है?

जावा के मामले में, यह जेनेरिक काम के तरीके के कारण है। जावा में, जेनेरिक एक संकलन-समय चाल है, जो आपको Image ऑब्जेक्ट को ArrayList<String> में डालने से रोकती है। हालांकि, जावा के जेनेरिक टाइप एरर के साथ कार्यान्वित किए जाते हैं: जेनेरिक टाइप जानकारी रन-टाइम के दौरान खो जाती है। यह संगतता कारणों के लिए था, क्योंकि जावा के जीवन में जेनेरिक काफी देर से जोड़े गए थे। इसका मतलब है कि, रन-टाइम, ArrayList<String> प्रभावी रूप से ArrayList<Object> (या बेहतर: केवल ArrayList है जो इसकी सभी विधियों में Object की अपेक्षा करता है और लौटाता है) जो आपके द्वारा मूल्य पुनर्प्राप्त करते समय String पर स्वचालित रूप से रहता है।

लेकिन int के बाद से Object से निकाले जाते हैं नहीं है, आप इसे एक ArrayList कि (कार्यावधि में) उम्मीद में नहीं डाल सकते Object और आप या तो एक Objectint में ढाला नहीं जा सकता है। इसका मतलब है कि आदिम int को उस प्रकार में लपेटा जाना चाहिए जो Object से Integer जैसा है।

सी # उदाहरण के लिए, अलग-अलग काम करता है। सी # में जेनिक्स को रनटाइम पर भी लागू किया जाता है और List<int> के साथ कोई मुक्केबाजी की आवश्यकता नहीं होती है। सी # में बॉक्सिंग तब होती है जब आप object जैसे संदर्भ प्रकार चर में int जैसे मान प्रकार को स्टोर करने का प्रयास करते हैं। int सी # में Object से सी # में विरासत में, object obj = 2 लिखना पूरी तरह से मान्य है, हालांकि int को बॉक्स किया जाएगा, जो संकलक द्वारा स्वचालित रूप से किया जाता है (Integer संदर्भ प्रकार उपयोगकर्ता या किसी भी चीज़ के संपर्क में आता है)।

+0

बस उम्मीद में कि मेरा प्रश्न देखा जाएगा मुझे पूछने की हिम्मत है: क्यों जावा ने ऑटोबॉक्सिंग के माध्यम से जेनेरिक के लिए आदिम लागू नहीं किया? मेरा मतलब है कि सूची संकलन के मामले में स्वचालित रूप से पूर्णांक को संकलित किया गया होगा .. – Dedyshka

11

बॉक्सिंग और अनबॉक्सिंग एक ऐसी आवश्यकता है जिससे भाषाएं (जैसे सी # और जावा) उनकी स्मृति आवंटन रणनीतियों को लागू करती हैं।

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

सी # ढेर-आवंटित प्रकार में मूल्य प्रकार (जैसे System.Int32 और System.DateTime) कहा जाता है और ढेर-आवंटित प्रकार संदर्भ प्रकार (जैसे System.Stream और System.String) कहा जाता है।

कुछ मामलों में संदर्भ प्रकार जैसे प्रतिबिंबित करने में सक्षम होना फायदेमंद है (प्रतिबिंब एक उदाहरण है) लेकिन ज्यादातर मामलों में, मुक्केबाजी और अनबॉक्सिंग से बचा जाता है।

+4

मूल्य प्रकारों और स्टैक-आधारित आवंटन के साथ सावधान। एरिक लिपर्ट के पास उस विषय पर दो महान ब्लॉग पोस्ट थे: http://blogs.msdn.com/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx और http: // ब्लॉग .msdn.com/ericlippert/archive/200/05/04/द-स्टैक-ए-ए-कार्यान्वयन-विवरण-भाग-दो.aspx – Joey

+2

AFAIK, सी # जेनेरिक कंटेनरों पर ऑटो-मुक्केबाजी का उपयोग नहीं करता है जब तक कि आप कुछ ऐसा निर्दिष्ट नहीं करते सूची । सी # जेनिक्स वैल्यू प्रकारों के लिए सी ++ के समान तरीके से काम करता है। http://msdn.microsoft.com/en-us/library/ms379564(VS.80).aspx –

2

मेरा मानना ​​है कि यह भी इसलिए है क्योंकि प्राइमेटिव ऑब्जेक्ट से प्राप्त नहीं होते हैं। मान लें कि आपके पास एक तरीका है जो पैरामीटर के रूप में कुछ भी स्वीकार करने में सक्षम होना चाहता है, उदाहरण के लिए।

class Printer { 
    public void print(Object o) { 
     ... 
    } 
} 

आप की तरह, कि विधि के लिए एक सरल आदिम मूल्य पारित करने के लिए आवश्यकता हो सकती है:

printer.print(5); 

आप ऐसा करने में सक्षम हो सकता है कि बिना मुक्केबाजी/unboxing, क्योंकि 5 एक आदिम है और एक नहीं है वस्तु। आप इस तरह की कार्यक्षमता को सक्षम करने के लिए प्रत्येक आदिम प्रकार के लिए प्रिंट विधि को अधिभारित कर सकते हैं, लेकिन यह एक दर्द है।

1

जावा और सी # (सी ++ के विपरीत) सब कुछ ऑब्जेक्ट बढ़ाता है, इसलिए आर्रेलिस्ट जैसे संग्रह वर्ग ऑब्जेक्ट या इसके किसी भी वंशज (मूल रूप से कुछ भी) को पकड़ सकते हैं।

प्रदर्शन कारणों से, जावा में प्राइमेटिव, या सी # में मूल्य प्रकार, को विशेष स्थिति दी गई थी। वे वस्तु नहीं हैं। आप कुछ ऐसा नहीं कर सकते (जावा में):

7.toString() 

भले ही toString ऑब्जेक्ट पर एक विधि है। निष्पादन के लिए इस नोड को पुल करने के लिए, समकक्ष वस्तुएं बनाई गई थीं। ऑटोबॉक्सिंग बॉयलरप्लेट कोड को अपने रैपर वर्ग में एक आदिम रखने के लिए हटा देता है और कोड को और अधिक पठनीय बनाने के लिए इसे फिर से बाहर ले जाता है।

सी # में मूल्य प्रकारों और वस्तुओं के बीच का अंतर अधिक ग्रे है।here देखें कि वे अलग कैसे हैं।

+0

सी # में, प्राइमेटिव को structs के रूप में कार्यान्वित किया जाता है (उदाहरण के लिए int सिस्टम नामस्थान में Int32 में परिभाषित किया गया है) जिसमें विधियां हैं 7. टॉस्ट्रिंग() ठीक काम करेगा। और जबकि सी # में सब कुछ ऑब्जेक्ट से निकला है, यह जावा के लिए मामला नहीं है। – JulianR

+3

@ जुलीयनआर: अधिक विशेष रूप से, सभी सीएलआर मान प्रकार सिस्टम से प्राप्त होते हैं। वैल्यू टाइप जो बदले में सिस्टम से प्राप्त होता है। ऑब्जेक्ट। System.ValueType कई प्रणालियों को ओवरराइड करता है। ऑब्जेक्ट की आभासी विधियां इस प्रकार मुक्केबाजी से परहेज करते हैं जब उन तरीकों को बुलाया जाता है। एकमात्र तरीके जो मुक्केबाजी के लिए बॉक्सिंग का कारण बनती हैं ऑब्जेक्ट। गेट टाइप और ऑब्जेक्ट। मेम्बरवाइडक्लोन। –

2

मैं केवल आपको जावा के लिए बता सकता हूं कि यह जेनेरिक में प्राइमेटिव प्रकारों का समर्थन क्यों नहीं करता है।

सबसे पहले समस्या यह थी कि जब जावा को आदिम प्रकार भी हो तो इस पर चर्चा करने के लिए सवाल उठाया गया। निश्चित रूप से वास्तविक प्रश्न की चर्चा में बाधा डाली।

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

अनुकूलता ersure (सामान्य प्रकार पैरामीटर जानकारी संकलन समय पर निकाला गया) जो भी कारण आप जावा में इतने सारे अनियंत्रित डाली चेतावनी प्राप्त है का उपयोग किया गया था।

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

और स्वचालित autoboxing/unboxing ऊपर देखें उपयोग के इस मामले में बहुत ज्यादा लागत autoboxing क्योंकि के लिए समर्थित नहीं किया गया था:

अन्य दृष्टिकोण एक सी # चुना है।

Java theory and practice: Generics gotchas

1

हर गैर सरणी गैर स्ट्रिंग ढेर पर संग्रहीत वस्तु एक 8- या 16-बाइट हैडर (32/64-बिट सिस्टम के लिए आकार), उस वस्तु के सार्वजनिक और की सामग्री के बाद होता है निजी क्षेत्र Arrays और तारों में उपरोक्त शीर्षलेख होता है, साथ ही प्रत्येक तत्व के आकार और आकार (प्रत्येक संभवतः आयामों की संख्या, प्रत्येक अतिरिक्त आयाम की लंबाई इत्यादि) की लंबाई को परिभाषित करने वाले कुछ और बाइट्स, इसके बाद पहले के सभी फ़ील्ड तत्व, फिर दूसरे के सभी क्षेत्रों, आदि। किसी ऑब्जेक्ट के संदर्भ को देखते हुए, सिस्टम आसानी से हेडर की जांच कर सकता है और यह निर्धारित कर सकता है कि यह किस प्रकार का है।

संदर्भ-प्रकार भंडारण स्थानों में चार- या आठ-बाइट मान होता है जो ढेर पर संग्रहीत ऑब्जेक्ट को विशिष्ट रूप से पहचानता है। वर्तमान कार्यान्वयन में, वह मान एक सूचक है, लेकिन इसे "ऑब्जेक्ट आईडी" के रूप में सोचने के लिए यह आसान (और अर्थात् समकक्ष) है।

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

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

ध्यान दें कि .NET में, सामान्य वर्गों और विधियों के रूप में घोषित करना संभव है। इस तरह की प्रत्येक घोषणा स्वचालित रूप से कक्षाओं या विधियों का एक परिवार उत्पन्न करती है जो कि किले को छोड़कर समान होती हैं, जिस पर वह कार्य करने की अपेक्षा करता है। यदि कोई Int32 को नियमित DoSomething<T>(T param) पर पास करता है, जो स्वचालित रूप से दिनचर्या का एक संस्करण उत्पन्न करेगा जिसमें T के प्रत्येक उदाहरण प्रभावी रूप से Int32 के साथ प्रतिस्थापित किया गया है। दिनचर्या के उस संस्करण को पता चलेगा कि टाइप T के रूप में घोषित प्रत्येक स्टोरेज स्थान Int32 रखता है, जैसे कि Int32 स्टोरेज स्थान का उपयोग करने के लिए नियमित रूप से हार्ड-कोड किया गया था, तो उन लोगों के साथ प्रकार की जानकारी स्टोर करना आवश्यक नहीं होगा खुद को स्थान।

संबंधित मुद्दे