2009-03-01 12 views
15

मैं कुछ महीनों के लिए जावा का अध्ययन किया गया है और अब सीजावा में संदर्भ द्वारा पारित होने और सी में एक सूचक को पार करने के बीच क्या अंतर है?

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

संदर्भ द्वारा गुजरने और पॉइंटर पास करने के बीच क्या अंतर है?

उत्तर

39

न तो जावा और न ही सी पास-दर-संदर्भ है। वे सख्ती से पास-दर-मूल्य दोनों हैं।

पास-बाय-संदर्भ अर्थशास्त्र का अर्थ है कि जब आप विधि में पैरामीटर का मान बदलते हैं, तो कॉलर तर्क में उस परिवर्तन को देखेगा।

अब, आप सोच रहे होंगे: "लेकिन जावा में यही मामला है! अगर मैं विधि के दौरान कोई ऑब्जेक्ट बदलता हूं, तो कॉलर उस परिवर्तन को देखता है।" वस्तु पैरामीटर नहीं है। पैरामीटर है चर - और यदि आप उस चर के मान को बदलते हैं, तो कॉलर उसे नहीं देख पाएगा। उदाहरण के लिए:

public void foo(Object x) 
{ 
    x = null; 
} 

public void caller() 
{ 
    Object y = new Object(); 
    foo(y); 
    // y is still not null! 
} 

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

आप my article about C# parameter passing को देखने के लिए देखने के लिए अगर जावा किया जो संभव होगा चाहते हो सकता है पारित-दर-संदर्भ अर्थ विज्ञान, के रूप में सी # करता है जब (और केवल जब) आप ref कीवर्ड का उपयोग करें।

आप इस विषय से संबंधित my Stack Overflow answer पर टिप्पणियां भी देखना चाह सकते हैं।

+2

बहुत, बहुत सच है। यह प्रोग्रामिंग के सबसे गलत समझा पहलुओं में से एक है जिसे मैंने कभी देखा है। – mmcdole

+0

हां, मान द्वारा पारित संदर्भ पहली चीजों में से एक है जो मुझे सी # –

+0

वाह में लटका दिया गया है! धन्यवाद जॉन, उत्कृष्ट जवाब! – neo2862

3

मतभेद सूक्ष्म हैं। एक असेंबली स्तर पर, दोनों मामलों में वस्तु का पता फ़ंक्शन में पास किया जाता है। हालांकि, सूचक मामले में पैरामीटर एक स्वतंत्र सूचक है जिसका उपयोग लक्ष्य ऑब्जेक्ट (* pch = 'x') को संशोधित करने के लिए किया जा सकता है या किसी भिन्न ऑब्जेक्ट (pch = "newstr") तक पहुंचने के लिए उपयोग किया जा सकता है। संदर्भ मामले में, पैरामीटर स्वचालित रूप से लक्षित ऑब्जेक्ट पर अप्रत्यक्ष हो जाता है।

1

यदि आप सी (सी ++ के बजाए) का अध्ययन कर रहे हैं, तो कोई संदर्भ नहीं है।

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

कई तरीकों से यह जावा में आप जो देखते हैं उसके समान है, सिवाय इसके कि जावा में आपको चीजों को स्पष्ट रूप से एक पॉइंटर में बदलने या उन्हें कम करने की आवश्यकता नहीं है। दूसरे शब्दों में, जब आप एक पॉइंटर पास करते हैं, तो पते को स्टैक पर कॉपी किया जाता है, इसलिए यदि आपका फ़ंक्शन पॉइंटर बदलता है (डेटा को इंगित करने के बजाए), तो फ़ंक्शन के साथ किए जाने पर परिवर्तन गायब हो जाते हैं। इसी तरह, जब आप जावा में किसी ऑब्जेक्ट संदर्भ को पास करते हैं, तो आप ऑब्जेक्ट की सामग्री को बदल सकते हैं (उदा।, फ़ंक्शंस कॉल करके), लेकिन एनोथ ऑब्जेक्ट पर इंगित करने के लिए varialbe को बदलने से आपके जाने के बाद कोई प्रभाव नहीं पड़ेगा।

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

+0

हे, क्या यह कहा जा सकता है कि: "पॉइंटर" डेटा प्रकार है, और "संदर्भ" डेटा से निपटने के लिए एक तरीका है *? एक बात है, दूसरी तकनीक है? * मैं यहां "विधि" का उपयोग करने की अस्पष्टता से बचने की कोशिश कर रहा हूं – Ziggy

+0

एक पॉइंटर निश्चित रूप से डेटा प्रकार है। हालांकि, सी ++ में (जो कि ज्यादातर सी लोग अंततः उपयोग करते हैं) एक संदर्भ प्रकार नामक डेटा प्रकार होता है। यह एक समस्या है क्योंकि सी ++ में वास्तविक संदर्भों और पॉइंटर्स के माध्यम से वास्तव में "संदर्भ से गुजरने" के दो तरीके हैं। तो "संदर्भ द्वारा पास" एक तरीका है। – Uri

2

कुछ बातें

  • सी (C++ के बावजूद) कोई संदर्भ है
  • जावा कोई संकेत
  • संकेत और संदर्भ के बीच का अंतर है, कि संकेत व्यावहारिक रूप से स्मृति के पते आप गणना कर सकते हैं कर रहे हैं साथ में। संदर्भ मूल्य से साथ
  • जावा और सी पास की गणना नहीं की जा सकती है (जब जावा में एक वस्तु गुजर, संदर्भ कार्य करने के लिए नकल की जाती है)
+0

मेरा सुझाव है कि आप अंतिम बुलेट से "डिफ़ॉल्ट रूप से" शब्द को हटा दें - सी और जावा पास मूल्य से, कहानी के अंत तक। –

2

मेरा मानना ​​है कि एक सूचक एक चर है कि एक संदर्भ होता है। & के साथ आप एक मेमोरी दिशा (संदर्भ) प्राप्त कर सकते हैं, और * आप स्मृति दिशा की सामग्री तक पहुंच सकते हैं। मैं The C programming Language पुस्तक का सुझाव देता हूं।

सादर

2

सच pass-by-reference मतलब है कि आप संदर्भ के लिए एक नया मूल्य प्रदान कर सकते हैं, और इस नए मूल्य सिर्फ अंदर बुलाया विधि की तरह बुला संदर्भ में दिखाई जाएगी।

जावा में, यह संभव नहीं है, क्योंकि object references are passed by value

1

इस बारे में एरिक लिपर्ट द्वारा हाल ही में एक लेख है। उन्होंने कहा कि सी # संकलक पर एक प्रोग्रामर है, लेकिन जो कुछ भी वे कहते हैं पर्याप्त व्यापकता जैसे कि जावा अन्य जीसी भाषाओं के लिए बढ़ाया जा करने के लिए वहाँ है: लेख से

http://blogs.msdn.com/ericlippert/archive/2009/02/17/references-are-not-addresses.aspx

उद्धरण:

प्वाइंटर सख्ती से कर रहे हैं संदर्भों से "अधिक शक्तिशाली"; आप संदर्भों के साथ कुछ भी कर सकते हैं जो आप पॉइंटर्स के साथ कर सकते हैं। [...]

पॉइंटर्स आमतौर पर पते के रूप में लागू होते हैं। एक पता एक संख्या है जो "बाइट्स की सरणी" में ऑफसेट है जो प्रक्रिया का संपूर्ण वर्चुअल एड्रेस स्पेस है। [...]

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

तो, सी # में एक संदर्भ कुछ अस्पष्ट चीज है जो आपको किसी ऑब्जेक्ट को संदर्भित करने देती है। आप संदर्भ के साथ कुछ भी नहीं कर सकते हैं इसे छोड़कर, और समानता के लिए किसी अन्य संदर्भ के साथ इसकी तुलना करें। और सी # में एक सूचक को एक पते के रूप में पहचाना जाता है।

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

+0

वह "संदर्भ द्वारा पारित" के बजाय संदर्भों के बारे में बात कर रहा है - वे संबंधित हैं लेकिन विभिन्न अवधारणाएं हैं। –

7

मैंने सोचा था कि अंतर यह था कि जावा में ऑब्जेक्ट्स के सभी ऑब्जेक्ट्स स्वचालित रूप से पॉइंटर्स के साथ किए जाते हैं, जहां सी में वास्तव में छोटे तारों और एम्परसैंड को छिड़काव होता है।

अवधारणात्मक, यह बिल्कुल सही है। अगर हम pedantic हैं (और यह एक अच्छी बात है), हम यह भी कह सकते हैं कि जावा में वस्तुओं को पारित नहीं किया गया है। पास किया जाता है केवल "पॉइंटर" होता है, जिसे जावा में संदर्भ कहा जाता है। सभी संकेत स्वचालित रूप से किया जाता है। तो जब आप सी में "objref.foo" के बजाय "objref-> foo" करते हैं और डॉट का उपयोग नहीं कर सकते हैं क्योंकि आप जावा में एक पॉइंटर के साथ काम करते हैं, तो आप अभी भी डॉट का उपयोग कर सकते हैं क्योंकि यह कुछ और नहीं जानता है वैसे भी सदस्यों का उपयोग करें। सी में, आप पॉइंटर पास कर सकते हैं (और यहां, यह वास्तव में पॉइंटर कहा जाता है) और आप ऑब्जेक्ट को स्वयं पास कर सकते हैं, इस मामले में एक प्रति पास हो जाती है। सी में, आप ऑब्जेक्ट तक पहुंचते हैं कि एक पॉइंटर स्टार या "->" का उपयोग करके संकेत द्वारा संदर्भित करता है। जावा में, वैसे भी ऑब्जेक्ट्स तक पहुंचने का एकमात्र तरीका डॉट (objref.member) का उपयोग कर रहे हैं।

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

0

im यकीन है कि जावा के बारे में है, लेकिन सी # या VB.net में नहीं आप refrence

static void Main(string[] args) 
    { 
     int x = 1; 
     Foo(ref x); 
     Console.WriteLine(x.ToString());//this will print 2 
    } 

    private static void Foo(ref int x) 
    { 
     x++; 
    } 

नोटिस से गुज़र कि एक्स 1 के बराबर है मूल्य द्वारा या refrence द्वारा

उदाहरण पारित कर सकते हैं, लेकिन जब आप कॉल फू में x द्वारा बढ़ाए जाने पर विधि फू और एक्स को गुजरने पर मूल मूल्य भी बढ़ जाता है

1

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

  • जावा समर्थित नहीं & ऑपरेटर तो आप जावा में ऑब्जेक्ट पता कैसे प्राप्त कर सकते हैं।
  • जावा संदर्भ में

MyClass object1 = नए MyClass उदाहरण के लिए वस्तु द्वारा किया जाता है();

MyClass object2 = object1;

यानी आपको लगता है कि ऑब्जेक्ट 1 और ऑब्जेक्ट 2 अलग और विशिष्ट ऑब्जेक्ट्स को संदर्भित करता है। हालांकि, यह गलत होगा। इसके बजाय, इस खंड निष्पादित करने के बाद, ऑब्जेक्ट 1 और ऑब्जेक्ट 2 दोनों एक ही ऑब्जेक्ट को संदर्भित करेंगे। यदि आप किसी भी एक प्रभाव में बदल जाते हैं।

* i.e MyClass obj = new MyClass() प्रारंभ करने के बाद आप ऑब्जेक्ट का पता नहीं बदल सकते हैं; C++ संदर्भ, वस्तु के साथ के रूप में आप केवल बदल सकते हैं आपत्ति उदाहरण मूल्य

नोट: प्रदान Java एक खास विशेषता object1 अशक्त करने के लिए स्थापित किया गया है, लेकिन अभी भी मूल object2 वस्तु को इंगित करता है।

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