सवाल जावा "पास-बाय-रेफरेंस" या "पास-बाय-वैल्यू" है?


मैंने हमेशा सोचा था कि जावा था पास-संदर्भ द्वारा

हालांकि, मैंने कुछ ब्लॉग पोस्ट देखे हैं (उदाहरण के लिए, यह ब्लॉग) जो दावा करते हैं कि यह नहीं है।

मुझे नहीं लगता कि मैं उनके द्वारा किए गए भेद को समझता हूं।

स्पष्टीकरण क्या है?


5495


मूल


मेरा मानना ​​है कि इस मुद्दे पर अधिकांश भ्रम इस तथ्य से है कि विभिन्न लोगों के पास "संदर्भ" शब्द की अलग-अलग परिभाषाएं हैं। सी ++ पृष्ठभूमि से आने वाले लोग मानते हैं कि "संदर्भ" का अर्थ सी ++ में क्या होना चाहिए, सी पृष्ठभूमि से लोग मानते हैं कि "संदर्भ" उनकी भाषा में "सूचक" जैसा होना चाहिए, और इसी तरह। चाहे यह कहना सही है कि संदर्भ द्वारा जावा पास वास्तव में "संदर्भ" के अर्थ पर निर्भर करता है। - Gravity
मैं लगातार मिली शब्दावली का उपयोग करने की कोशिश करता हूं मूल्यांकन रणनीति लेख। यह ध्यान दिया जाना चाहिए कि, हालांकि लेख बताता है कि समुदाय द्वारा शब्दों में काफी भिन्नता है जोर देता है कि अर्थशास्त्र के लिए call-by-value तथा call-by-reference एक बहुत ही महत्वपूर्ण तरीके से भिन्न है। (व्यक्तिगत रूप से मैं उपयोग करना पसंद करता हूं call-by-object-sharing इन दिनों खत्म हो गया call-by-value[-of-the-reference], क्योंकि यह उच्च स्तर पर अर्थशास्त्र का वर्णन करता है और इसके साथ संघर्ष नहीं करता है call-by-value, कौन कौन से है अंतर्निहित कार्यान्वयन।)
@ गुरुत्वाकर्षण: क्या आप जा सकते हैं और अपनी टिप्पणी को बड़े बिलबोर्ड या कुछ पर डाल सकते हैं? संक्षेप में यह पूरी समस्या है। और यह दिखाता है कि यह पूरी बात अर्थशास्त्र है। यदि हम किसी संदर्भ की मूल परिभाषा से सहमत नहीं हैं, तो हम इस प्रश्न के उत्तर पर सहमत नहीं होंगे :) - MadConan
मुझे लगता है कि भ्रम "संदर्भ द्वारा पारित" बनाम "संदर्भ अर्थशास्त्र" है। जावा संदर्भ अर्थशास्त्र के साथ पास-दर-मूल्य है। - spraff
@ गुरुत्वाकर्षण, जबकि आप हैं पूर्ण रूप से सी ++ से आने वाले लोगों में सही रूप से "संदर्भ" शब्द के बारे में एक अलग अंतर्ज्ञान सेट होगा, मुझे व्यक्तिगत रूप से विश्वास है कि शरीर को "द्वारा" में अधिक दफनाया गया है। "पास पास" यह भ्रमित कर रहा है कि यह जावा में "पासिंग ए" से बिल्कुल अलग है। सी ++ में, हालांकि यह बोलचाल नहीं है। सी ++ में आप "संदर्भ पारित करना" कह सकते हैं, और यह है समझा कि यह गुजर जाएगा swap(x,y) परीक्षा।


जवाब:


जावा हमेशा होता है पास--मूल्य से। दुर्भाग्य से, उन्होंने किसी ऑब्जेक्ट का स्थान "संदर्भ" कहने का निर्णय लिया। जब हम किसी ऑब्जेक्ट का मान पास करते हैं, तो हम पास कर रहे हैं संदर्भ इसके लिए यह शुरुआती लोगों को भ्रमित कर रहा है।

यह इस प्रकार चलता है:

public static void main(String[] args) {
    Dog aDog = new Dog("Max");
    // we pass the object to foo
    foo(aDog);
    // aDog variable is still pointing to the "Max" dog when foo(...) returns
    aDog.getName().equals("Max"); // true
    aDog.getName().equals("Fifi"); // false 
}

public static void foo(Dog d) {
    d.getName().equals("Max"); // true
    // change d inside of foo() to point to a new Dog instance "Fifi"
    d = new Dog("Fifi");
    d.getName().equals("Fifi"); // true
}

उपरोक्त उदाहरण में aDog.getName() अभी भी वापस आ जाएगा "Max"। महत्व aDog अंदर main समारोह में नहीं बदला गया है foo उसके साथ Dog  "Fifi" क्योंकि वस्तु संदर्भ मूल्य से पारित किया जाता है। यदि यह संदर्भ द्वारा पारित किया गया था, तो aDog.getName() में main लौटूंगा "Fifi" कॉल करने के बाद foo

इसी तरह:

public static void main(String[] args) {
    Dog aDog = new Dog("Max");
    foo(aDog);
    // when foo(...) returns, the name of the dog has been changed to "Fifi"
    aDog.getName().equals("Fifi"); // true
}

public static void foo(Dog d) {
    d.getName().equals("Max"); // true
    // this changes the name of d to be "Fifi"
    d.setName("Fifi");
}

उपर्युक्त उदाहरण में, Fifi कॉल करने के बाद कुत्ते का नाम है foo(aDog) क्योंकि ऑब्जेक्ट का नाम अंदर सेट किया गया था foo(...)। कोई भी ऑपरेशन जो foo पर प्रदर्शन करता है d ऐसे हैं कि, सभी व्यावहारिक उद्देश्यों के लिए, वे प्रदर्शन कर रहे हैं aDog खुद (जब छोड़कर d एक अलग बिंदु पर बदल दिया गया है Dog उदाहरण की तरह d = new Dog("Boxer"))।


4741



क्या यह आंतरिक विवरण के साथ इस मुद्दे को थोड़ा उलझन में नहीं डाल रहा है? 'संदर्भ को पारित करने' और 'संदर्भ के मूल्य को पारित करने' के बीच कोई वैचारिक अंतर नहीं है, यह मानते हुए कि आपका मतलब है 'ऑब्जेक्ट में आंतरिक सूचक का मान'। - izb
लेकिन एक सूक्ष्म अंतर है। पहले उदाहरण को देखो। अगर यह पूरी तरह से संदर्भ द्वारा पारित किया गया था, तो ADog.name "फिफी" होगा। यह नहीं है - जो संदर्भ आप प्राप्त कर रहे हैं वह एक मान संदर्भ है कि यदि फ़ंक्शन से बाहर निकलने पर ओवरराइट किया जाएगा। - erlando
@Lorenzo: नहीं, जावा में सब कुछ मूल्य से गुजरता है। Primitives मूल्य से पारित कर रहे हैं, और वस्तु संदर्भ मूल्य से पारित कर रहे हैं। वस्तुओं को कभी भी एक विधि में पारित नहीं किया जाता है, लेकिन वस्तुएं हमेशा ढेर में होती हैं और केवल वस्तु का संदर्भ विधि को पास किया जाता है। - Esko Luontola
ऑब्जेक्ट पास करने की कल्पना करने के लिए एक अच्छे तरीके से मेरा प्रयास: एक गुब्बारा की कल्पना करो। एक एफएक्सएन को कॉल करना गुब्बारे के लिए दूसरी स्ट्रिंग को बांधना और लाइन को एफएक्सएन को सौंपना है। पैरामीटर = नया गुब्बारा () उस स्ट्रिंग को काट देगा और एक नया गुब्बारा बनाएगा (लेकिन इसका मूल गुब्बारा पर कोई प्रभाव नहीं पड़ता है)। पैरामीटर.pop () अभी भी इसे पॉप करेगा हालांकि यह स्ट्रिंग का पालन करता है, मूल गुब्बारा। जावा मूल्य से गुजरता है, लेकिन पारित मूल्य गहरा नहीं है, यह उच्चतम स्तर पर है, यानी एक आदिम या सूचक। भ्रमित न करें कि गहरे पास-दर-मूल्य के साथ जहां वस्तु पूरी तरह से क्लोन और पास हो जाती है। - dhackner
भ्रमित करने वाला यह है कि ऑब्जेक्ट संदर्भ वास्तव में पॉइंटर्स हैं। शुरुआत में सूर्य ने उन्हें पॉइंटर्स कहा। फिर विपणन ने सूचित किया कि "सूचक" एक बुरा शब्द था। लेकिन आप अभी भी NullPointerException में "सही" नामकरण देखते हैं। - Prof. Falken


मैंने अभी आपको संदर्भित किया है मेरा लेख

जावा स्पेक का कहना है कि जावा में सबकुछ पास-बाय-वैल्यू है। जावा में "पास-बाय-रेफरेंस" जैसी कोई चीज़ नहीं है।

इसे समझने की कुंजी यह है कि कुछ ऐसा है

Dog myDog;

है नहीं एक कुत्ता; यह वास्तव में एक है सूचक एक कुत्ते को

इसका मतलब क्या है, जब आपके पास है

Dog myDog = new Dog("Rover");
foo(myDog);

आप अनिवार्य रूप से गुजर रहे हैं पता बनाए गए Dog ऑब्जेक्ट foo तरीका।

(मैं अनिवार्य रूप से कहता हूं क्योंकि जावा पॉइंटर्स प्रत्यक्ष पते नहीं हैं, लेकिन इस तरह उनके बारे में सोचना सबसे आसान है)

मान लीजिए Dog ऑब्जेक्ट मेमोरी एड्रेस 42 पर रहता है। इसका मतलब है कि हम विधि को 42 पास करते हैं।

अगर विधि को परिभाषित किया गया था

public void foo(Dog someDog) {
    someDog.setName("Max");     // AAA
    someDog = new Dog("Fifi");  // BBB
    someDog.setName("Rowlf");   // CCC
}

चलो देखते हैं कि क्या हो रहा है।

  • पैरामीटर someDog मूल्य 42 पर सेट है
  • लाइन "एएए" पर
    • someDog के बाद किया जाता है Dog यह इंगित करता है (द Dog पते पर वस्तु 42)
    • उस Dog (पता 42 पर एक) को अपना नाम मैक्स में बदलने के लिए कहा जाता है
  • लाइन पर "बीबीबी"
    • एक नया Dog बनाया गया है। मान लीजिए कि वह 74 पर है
    • हम पैरामीटर असाइन करते हैं someDog 74 तक
  • लाइन "सीसीसी" पर
    • कुछ डॉग का पालन किया जाता है Dog यह इंगित करता है (द Dog पते पर वस्तु 74)
    • उस Dog (पता 74 पर एक) को अपना नाम रोवल में बदलने के लिए कहा जाता है
  • फिर, हम वापस आते हैं

अब चलिए सोचें कि विधि के बाहर क्या होता है:

किया myDog परिवर्तन?

कुंजी है

ध्यान में रखते हुए myDog एक है सूचक, और वास्तविक नहीं Dog, जवाब न है। myDog अभी भी मूल्य 42 है; यह अभी भी मूल को इंगित कर रहा है Dog(लेकिन ध्यान दें कि "एएए" रेखा के कारण, इसका नाम अब "मैक्स" है - अभी भी वही कुत्ता; myDogका मूल्य नहीं बदला है।)

यह पूरी तरह से मान्य है का पालन करें एक पता और इसके अंत में क्या बदलता है; हालांकि, परिवर्तनीय नहीं बदलता है।

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

सी ++ में, एडा, पास्कल और अन्य भाषाएं जो पास-बाय-रेफरेंस का समर्थन करती हैं, आप वास्तव में पारित चर को बदल सकते हैं।

यदि जावा पास-दर-संदर्भ अर्थशास्त्र था, तो foo जिस तरीके से हमने ऊपर परिभाषित किया है वह बदल जाएगा myDog जब यह सौंपा गया था इंगित कर रहा था someDog लाइन बीबीबी पर।

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


2639



यही कारण है कि "जावा में पॉइंटर्स नहीं हैं" सामान्य बचना इतना भ्रामक है। - Beska
तुम गलत हो, इमो। "यह ध्यान में रखते हुए कि मेरा डॉग एक सूचक है, न कि एक वास्तविक कुत्ता, जवाब नहीं है। मेरे डॉग में अभी भी मूल्य 42 है; यह अभी भी मूल कुत्ते को इंगित कर रहा है।" myDog का मूल्य 42 है लेकिन इसके नाम तर्क में अब // एएए लाइन पर "रोवर" की बजाय "अधिकतम" है। - Özgür
इस तरह से इसके बारे में सोचो। किसी के पास एन आर्बर, एमआई (मेरा गृहनगर, जाओ नीला!) का पता है, जिसे "एनएबरबोरोकेशन" नामक पेपर की पर्ची पर रखा गया है। आप इसे "myDestination" नामक पेपर के टुकड़े पर कॉपी करते हैं। आप "myDestination" ड्राइव कर सकते हैं और एक पेड़ लगा सकते हैं। आपने उस स्थान पर शहर के बारे में कुछ बदल दिया हो सकता है, लेकिन यह किसी भी पेपर पर लिखे गए एलएटी / एलओएन को नहीं बदलता है। आप "myDestination" पर LAT / LON बदल सकते हैं लेकिन यह "AnnArborLocation" नहीं बदलता है। क्या उससे मदद हुई? - Scott Stanchfield
@ स्कॉट स्टैंचफील्ड: मैंने एक साल पहले आपके लेख को पढ़ा था और यह वास्तव में मेरे लिए चीजों को स्पष्ट करने में मदद करता था। धन्यवाद! क्या मैं नम्रता से थोड़ा सा सुझाव सुझा सकता हूं: आपको यह उल्लेख करना चाहिए कि वास्तव में एक विशिष्ट शब्द है जो इस मूल्य का वर्णन करता है "मूल्य द्वारा कॉल करें जहां मूल्य एक संदर्भ है" जिसका आविष्कार बारबरा लिस्कोव ने किया था, जिसमें उसकी सीएलयू भाषा की मूल्यांकन रणनीति का वर्णन किया गया था 1 9 74, भ्रम से बचने के लिए जैसे आपका लेख पता चलता है: साझा करके कॉल करें (कई बार बुलाना ऑब्जेक्ट-शेयरिंग द्वारा कॉल करें या केवल वस्तु द्वारा कॉल करें), जो सैद्धांतिक रूप से पूरी तरह से वर्णन करता है। - Jörg W Mittag
@ गेवोर्ग - सी / सी ++ भाषाओं में "पॉइंटर" की अवधारणा नहीं है। ऐसी अन्य भाषाएं हैं जो पॉइंटर्स का उपयोग करती हैं लेकिन पॉइंटर्स के समान प्रकार के हेरफेर की अनुमति नहीं देती हैं जो सी / सी ++ अनुमति देते हैं। जावा पॉइंटर्स है; वे सिर्फ शरारत के खिलाफ सुरक्षित हैं। - Scott Stanchfield


जावा हमेशा संदर्भ द्वारा मूल्य से तर्क पास करता है।


मुझे इसे एक के माध्यम से समझाएं उदाहरण:

public class Main{
     public static void main(String[] args){
          Foo f = new Foo("f");
          changeReference(f); // It won't change the reference!
          modifyReference(f); // It will modify the object that the reference variable "f" refers to!
     }
     public static void changeReference(Foo a){
          Foo b = new Foo("b");
          a = b;
     }
     public static void modifyReference(Foo c){
          c.setAttribute("c");
     }
}

मैं इसे चरणों में समझाऊंगा:

  1. नाम का एक संदर्भ घोषित करना f प्रकार का Foo और इसे प्रकार की एक नई वस्तु को असाइन करें Foo एक विशेषता के साथ "f"

    Foo f = new Foo("f");
    

    enter image description here

  2. विधि पक्ष से, प्रकार का एक संदर्भ Foo एक नाम के साथ a घोषित किया गया है और इसे शुरू में सौंपा गया है null

    public static void changeReference(Foo a)
    

    enter image description here

  3. जैसा कि आप विधि को कॉल करते हैं changeReference, संदर्भ a एक तर्क के रूप में पारित वस्तु को सौंपा जाएगा।

    changeReference(f);
    

    enter image description here

  4. नाम का एक संदर्भ घोषित करना b प्रकार का Foo और इसे प्रकार की एक नई वस्तु को असाइन करें Foo एक विशेषता के साथ "b"

    Foo b = new Foo("b");
    

    enter image description here

  5. a = b संदर्भ फिर से असाइन कर रहा है a नहीं f उस वस्तु के लिए जिसका गुण है "b"

    enter image description here


  6. जैसा कि आप कॉल करते हैं modifyReference(Foo c) विधि, एक संदर्भ c विशेषता के साथ वस्तु को बनाया और सौंपा गया है "f"

    enter image description here

  7. c.setAttribute("c"); संदर्भ के ऑब्जेक्ट की विशेषता को बदल देगा c इसके लिए इंगित करता है, और यह वही वस्तु है जो संदर्भ है f इसे इंगित करता है।

    enter image description here

मुझे आशा है कि अब आप समझेंगे कि कैसे जावा में तर्क काम करता है :)


1392



+1 अच्छी चीजें। अच्छा आरेख मुझे यहां एक अच्छा संक्षिप्त पृष्ठ भी मिला adp-gmbh.ch/php/pass_by_reference.html ठीक है, मैं मानता हूं कि यह PHP में लिखा गया है, लेकिन यह अंतर समझने के लिए बहुत ही महत्वपूर्ण है जो मुझे लगता है कि महत्वपूर्ण है (और आपकी आवश्यकताओं के लिए उस अंतर को कैसे छेड़छाड़ करना है)। - DaveM
@ Eng.Fouad यह एक अच्छा स्पष्टीकरण है लेकिन अगर a उसी वस्तु को इंगित करता है f (और वस्तु की अपनी प्रति कभी नहीं मिलती है f इंगित करता है), वस्तु का उपयोग करके किए गए किसी भी बदलाव में a संशोधित करना चाहिए f साथ ही (क्योंकि वे दोनों एक ही वस्तु के साथ काम कर रहे हैं), इसलिए किसी बिंदु पर a अपना खुद का होना चाहिए प्रतिलिपि वस्तु का f इशारा करना। - Mr D
@ एमआरडी जब 'ए' एक ही ऑब्जेक्ट 'एफ' को इंगित करता है तो 'ए' के ​​माध्यम से उस ऑब्जेक्ट में किए गए किसी भी बदलाव को 'एफ' के माध्यम से भी देखा जा सकता है, लेकिन यह 'f' को बदल नहीं सकता है। 'एफ' अभी भी एक ही वस्तु को इंगित करता है। आप ऑब्जेक्ट को पूरी तरह से बदल सकते हैं, लेकिन आप कभी भी 'एफ' अंक को बदल नहीं सकते हैं। यह मौलिक मुद्दा है कि किसी कारण से कुछ लोग समझ नहीं सकते हैं। - Mike Braun
यह मुझे मिला सबसे अच्छा स्पष्टीकरण है। वैसे, बुनियादी स्थिति के बारे में क्या? उदाहरण के लिए, तर्क को एक int प्रकार की आवश्यकता होती है, क्या यह अभी भी एक int चर की प्रति को तर्क में पास करता है? - allenwang
आरेख बहुत उपयोगी था - Ivan Kaloyanov


यह आपको कुछ अंतर्दृष्टि देगा कि जावा वास्तव में इस बिंदु पर कैसे काम करता है कि जावा के संदर्भ में गुजरने या मूल्य से गुजरने के बारे में आपकी अगली चर्चा में आप केवल मुस्कान करेंगे :-)

चरण एक कृपया अपने दिमाग से मिटा दें कि शब्द 'पी' से शुरू होता है "_ _ _ _ _ _ _", खासकर अगर आप अन्य प्रोग्रामिंग भाषाओं से आते हैं। जावा और 'पी' को एक ही पुस्तक, फोरम, या यहां तक ​​कि txt में भी नहीं लिखा जा सकता है।

चरण दो याद रखें कि जब आप किसी ऑब्जेक्ट को किसी विधि में पास करते हैं तो आप ऑब्जेक्ट संदर्भ पास कर रहे हैं, न कि ऑब्जेक्ट स्वयं।

  • छात्र: मास्टर, क्या इसका मतलब यह है कि जावा पास-दर-संदर्भ है?
  • स्वामी: घास का मैदान, संख्या

अब सोचें कि ऑब्जेक्ट का संदर्भ / चर क्या करता है / है:

  1. एक वेरिएबल बिट्स रखता है जो जेवीएम को बताता है कि मेमोरी (हीप) में संदर्भित ऑब्जेक्ट को कैसे प्राप्त किया जाए।
  2. एक विधि के लिए तर्क पारित करते समय आप संदर्भ चर पारित नहीं कर रहे हैं, लेकिन संदर्भ चर में बिट्स की एक प्रति। ऐसा कुछ: 3bad086a। 3bad086a पारित वस्तु को प्राप्त करने के लिए एक तरीका का प्रतिनिधित्व करता है।
  3. तो आप बस 3bad086a पास कर रहे हैं कि यह संदर्भ का मूल्य है।
  4. आप संदर्भ का मूल्य पारित कर रहे हैं, न कि संदर्भ स्वयं (और वस्तु नहीं)।
  5. यह मान वास्तव में कॉपी किया गया है और विधि को दिया गया है

निम्नलिखित में (कृपया इसे संकलित / निष्पादित करने का प्रयास न करें ...):

1. Person person;
2. person = new Person("Tom");
3. changeName(person);
4.
5. //I didn't use Person person below as an argument to be nice
6. static void changeName(Person anotherReferenceToTheSamePersonObject) {
7.     anotherReferenceToTheSamePersonObject.setName("Jerry");
8. }

क्या होता है?

  • चर व्यक्ति लाइन # 1 में बनाया गया है और शुरुआत में यह शून्य है।
  • एक नया व्यक्ति ऑब्जेक्ट लाइन # 2 में बनाया गया है, स्मृति में संग्रहीत, और चर व्यक्ति व्यक्ति वस्तु का संदर्भ दिया जाता है। यही है, इसका पता। मान लें 3bad086a।
  • चर व्यक्ति ऑब्जेक्ट का पता धारण करना # 3 में फ़ंक्शन पर पास किया गया है।
  • लाइन # 4 में आप चुप्पी की आवाज सुन सकते हैं
  • लाइन # 5 पर टिप्पणी की जांच करें
  • एक विधि स्थानीय चर -anotherReferenceToTheSamePersonObject- बनाया गया है और फिर जादू # 6 में जादू आता है:
    • चर / संदर्भ व्यक्ति बिट-बाय-बिट कॉपी किया गया है और पास किया गया है anotherReferenceToTheSamePersonObject समारोह के अंदर।
    • व्यक्ति के कोई नए उदाहरण नहीं बनाए जाते हैं।
    • दोनों "व्यक्ति" तथा "anotherReferenceToTheSamePersonObject"3bad086a का वही मान रखें।
    • इसे आजमाएं लेकिन व्यक्ति == किसी अन्य संदर्भ के लिए TheSamePersonObject सत्य होगा।
    • दोनों चरों में संदर्भ की पहचान की प्रतियां हैं और वे दोनों एक ही व्यक्ति वस्तु, ढेर पर समान वस्तु और एक प्रतिलिपि नहीं देखते हैं।

एक तस्वीर एक हजार शब्दों के बराबर होती है:

Pass by Value

ध्यान दें कि anotherReferenceToTheSamePersonObject तीर ऑब्जेक्ट की ओर निर्देशित है और परिवर्तनीय व्यक्ति की ओर नहीं!

अगर आपको यह नहीं मिला तो बस मुझ पर भरोसा करें और याद रखें कि यह कहना बेहतर है जावा मूल्य से गुजरता है। कुंआ, संदर्भ मूल्य से गुजरें। ओह ठीक है, यहां तक ​​कि बेहतर है पारित-दर-प्रति-ऑफ-द-चर-मान! ;)

अब मुझे नफरत करने के लिए स्वतंत्र महसूस करें लेकिन ध्यान दें कि यह दिया गया है आदिम डेटा प्रकारों और ऑब्जेक्ट्स को पार करने के बीच कोई अंतर नहीं है विधि तर्क के बारे में बात करते समय।

आप हमेशा संदर्भ के मूल्य के बिट्स की एक प्रति पास करते हैं!

  • यदि यह एक आदिम डेटा प्रकार है तो इन बिट्स में आदिम डेटा प्रकार का मूल्य होगा।
  • यदि यह ऑब्जेक्ट है तो बिट्स में उस पते का मान होगा जो JVM को ऑब्जेक्ट को कैसे प्राप्त करें।

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


उपरोक्त परिवर्तननाम फ़ंक्शन पारित संदर्भ की वास्तविक सामग्री (बिट मान) को संशोधित करने में सक्षम नहीं होगा। दूसरे शब्द में परिवर्तननाम व्यक्ति व्यक्ति को किसी अन्य वस्तु का संदर्भ नहीं दे सकता है।


बेशक आप इसे छोटा कर सकते हैं और बस यही कह सकते हैं जावा पास-दर-मूल्य है!


651



क्या आप पॉइंटर्स का मतलब है? .. अगर मैं इसे सही तरीके से प्राप्त करता हूं, तो अंदर public void foo(Car car){ ... }, car स्थानीय है foo और इसमें ऑब्जेक्ट का ढेर स्थान शामिल है? तो अगर मैं बदलता हूँ carद्वारा मूल्य car = new Car(), यह ढेर पर विभिन्न वस्तु को इंगित करेगा? और अगर मैं बदलता हूं carसंपत्ति का मूल्यांकन car.Color = "Red", ढेर में वस्तु द्वारा इंगित किया गया car संशोधित किया जाएगा। इसके अलावा, यह सी # में भी वही है? कृपया उत्तर दें! धन्यवाद! - dpp
@domanokz तुम मुझे मार रहे हो, कृपया फिर से यह शब्द मत कहो! ;) ध्यान दें कि मैं 'संदर्भ' के बिना भी इस प्रश्न का उत्तर दे सकता था। यह एक शब्दावली मुद्दा है और 'पी इसे और भी खराब बना देता है। दुर्भाग्यवश मुझे और स्कॉट के अलग-अलग विचार हैं। मुझे लगता है कि आपको जावा में यह कैसे काम करता है, अब आप इसे बाय-वैल्यू, बाय-ऑब्जेक्ट-शेयरिंग, बाय-कॉपी-ऑफ-द-वेरिएबल-वैल्यू से कॉल कर सकते हैं, या किसी अन्य चीज़ के साथ आने में स्वतंत्र महसूस कर सकते हैं! मुझे वास्तव में तब तक परवाह नहीं है जब तक आपको यह पता चलता है कि यह कैसे काम करता है और किस प्रकार के चर के प्रकार में है: बस एक पीओ बॉक्स पता! ;) - Gevorg
बस आप की तरह लगता है एक संदर्भ पारित किया? मैं इस तथ्य को चैंपियन करने जा रहा हूं कि जावा अभी भी एक प्रतिलिपि पास-दर-संदर्भ भाषा है। तथ्य यह है कि यह एक प्रतिलिपि संदर्भ है शब्दावली को नहीं बदलता है। दोनों संदर्भ अभी भी एक ही वस्तु को इंगित करते हैं। यह एक शुद्धवादी तर्क है ... - John Strickler
मुझे लगता है कि जावा पॉइंटर्स के साथ दिमाग में डिजाइन किया गया है। अन्यथा, क्यों NullPointerException मौजूद? फिर भी, इस अद्भुत स्पष्टीकरण के लिए, पॉइंटर्स प्राप्त करने से यह जटिल हो जाएगा - brain storm
तो सैद्धांतिक रेखा # 9 पर ड्रॉप System.out.println(person.getName()); क्या दिखाएगा? "टॉम" या "जेरी"? यह आखिरी चीज है जो मुझे इस भ्रम को बाधित करने में मदद करेगी। - TheBrenny


जावा हमेशा मूल्य से गुजरता है, बिना किसी अपवाद के, कभी

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

तो, एक विधि बुलाते समय

  • आदिम तर्क के लिए (int, long, आदि), मूल्य से पास है वास्तविक मूल्य आदिम (उदाहरण के लिए, 3) के।
  • वस्तुओं के लिए, मूल्य से पास का मूल्य है वस्तु का संदर्भ

तो अगर आपके पास है doSomething(foo) तथा public void doSomething(Foo foo) { .. } दो फूओ की प्रतिलिपि बनाई गई है संदर्भ जो एक ही वस्तु को इंगित करता है।

स्वाभाविक रूप से, किसी ऑब्जेक्ट के संदर्भ में मूल्य से गुज़रना संदर्भ के आधार पर किसी ऑब्जेक्ट को पास करने (और अभ्यास से अलग करने योग्य) जैसा दिखता है।


561



चूंकि प्राइमेटिव के मूल्य अपरिवर्तनीय हैं (स्ट्रिंग की तरह), दोनों मामलों के बीच का अंतर वास्तव में प्रासंगिक नहीं है। - Paŭlo Ebermann
ठीक ठीक। आप सभी के लिए अवलोकन योग्य JVM व्यवहार के माध्यम से बता सकते हैं, प्राइमेटिव को संदर्भ द्वारा पारित किया जा सकता है और ढेर पर रह सकता है। वे नहीं करते हैं, लेकिन यह वास्तव में किसी भी तरह से देखने योग्य नहीं है। - Gravity
primitives अपरिवर्तनीय हैं? जावा 7 में नया है? - Carlos Heuberger
@ करलोस हेबरर, "प्राइमेटिव्स अपरिवर्तनीय हैं?"। मुद्दा यह है कि आप कर सकते हैं नाटक कि 'primitives' वास्तव में (mutable) हैं संदर्भ अपरिवर्तनीय वस्तुओं के लिए। - Aaron McDaid
पॉइंटर्स अपरिवर्तनीय हैं, सामान्य रूप से primitives mutable हैं। स्ट्रिंग भी एक आदिम नहीं है, यह एक वस्तु है। इसके अलावा, स्ट्रिंग की अंतर्निहित संरचना एक परिवर्तनीय सरणी है। इसके बारे में एकमात्र अपरिवर्तनीय चीज लंबाई है, जो सरणी की अंतर्निहित प्रकृति है। - kingfrito_5005


जावा मूल्य से संदर्भ पास करता है।

तो आप पारित संदर्भ को बदल नहीं सकते हैं।


279



लेकिन वह चीज़ जो दोहराई जा रही है "आप तर्कों में पारित वस्तुओं के मूल्य को नहीं बदल सकते हैं" स्पष्ट रूप से झूठा है। आप उन्हें किसी भिन्न ऑब्जेक्ट को संदर्भित करने में सक्षम नहीं हो सकते हैं, लेकिन आप अपनी विधियों को कॉल करके अपनी सामग्री बदल सकते हैं। आईएमओ का मतलब है कि आप संदर्भों के सभी लाभ खो देते हैं, और कोई अतिरिक्त गारंटी नहीं प्राप्त करते हैं। - Timmmm
मैंने कभी नहीं कहा "आप तर्कों में पारित वस्तुओं के मूल्य को नहीं बदल सकते हैं"। मैं कहूंगा "आप एक विधि तर्क के रूप में पारित ऑब्जेक्ट संदर्भ का मान नहीं बदल सकते हैं", जो जावा भाषा के बारे में एक सच्चा बयान है। जाहिर है आप वस्तु की स्थिति बदल सकते हैं (जब तक यह अपरिवर्तनीय नहीं है)। - ScArcher2
ध्यान रखें कि आप वास्तव में जावा में वस्तुओं को पार नहीं कर सकते हैं; वस्तुओं ढेर पर रहते हैं। संकेत ऑब्जेक्ट्स को पास किया जा सकता है (जिसे कॉल विधि के लिए स्टैक फ्रेम पर कॉपी किया जाता है)। तो आप पास-इन मान (सूचक) को कभी भी नहीं बदलते हैं, लेकिन आप इसका पालन करने के लिए स्वतंत्र हैं और उस चीज को उस ढेर पर बदल दें जिस पर यह इंगित करता है। यह पास-दर-मूल्य है। - Scott Stanchfield
बस आप की तरह लगता है एक संदर्भ पारित किया? मैं इस तथ्य को चैंपियन करने जा रहा हूं कि जावा अभी भी एक प्रतिलिपि पास-दर-संदर्भ भाषा है। तथ्य यह है कि यह एक प्रतिलिपि संदर्भ है शब्दावली को नहीं बदलता है। दोनों संदर्भ अभी भी एक ही वस्तु को इंगित करते हैं। यह एक शुद्धवादी तर्क है ... - John Strickler
जावा किसी ऑब्जेक्ट को पास नहीं करता है, यह ऑब्जेक्ट में पॉइंटर का मान पास करता है। यह एक नए चर में मूल ऑब्जेक्ट के उस स्मृति स्थान पर एक नया सूचक बनाता है। यदि आप इस पॉइंटर वैरिएबल के मान (उस मेमोरी एड्रेस को इंगित करते हैं) को विधि में बदलते हैं, तो विधि कॉलर में उपयोग किया जाने वाला मूल पॉइंटर अनमोडिफाइड रहता है। यदि आप पैरामीटर को संदर्भ में कॉल कर रहे हैं तो तथ्य यह है कि यह एक है प्रतिलिपि मूल संदर्भ का, मूल संदर्भ स्वयं ऐसा नहीं है कि ऑब्जेक्ट के दो संदर्भ अब हैं कि यह पास-दर-मूल्य है - theferrit32


मुझे लगता है कि "पास-बाय-रेफरेंस बनाम पास-बाय-वैल्यू" के बारे में बहस करना बहुत उपयोगी नहीं है।

यदि आप कहते हैं, "जावा पास-बाय-जो भी (संदर्भ / मान) है, किसी भी मामले में, आप एक पूर्ण उत्तर प्रदान नहीं कर रहे हैं। यहां कुछ अतिरिक्त जानकारी दी गई है जो उम्मीद में मदद करेंगे कि स्मृति में क्या हो रहा है।

जावा कार्यान्वयन से पहले हम ढेर / ढेर पर क्रैश कोर्स: एक कैफेटेरिया में प्लेटों के ढेर की तरह, एक अच्छी व्यवस्थित फैशन में स्टैक चालू और बंद हो जाते हैं। ढेर में मेमोरी (गतिशील स्मृति के रूप में भी जाना जाता है) खतरनाक और असंगठित है। JVM बस जहां भी हो सकता है वहां स्थान पाता है, और इसे मुक्त करता है क्योंकि इसका उपयोग करने वाले चर की आवश्यकता नहीं होती है।

ठीक है। सबसे पहले, स्थानीय प्राइमेटिव ढेर पर जाते हैं। तो यह कोड:

int x = 3;
float y = 101.1f;
boolean amIAwesome = true;

इसके परिणाम:

primitives on the stack

जब आप किसी ऑब्जेक्ट को घोषित करते हैं और तत्काल करते हैं। वास्तविक वस्तु ढेर पर जाती है। ढेर पर क्या चल रहा है? ढेर पर वस्तु का पता। सी ++ प्रोग्रामर इसे एक पॉइंटर कहते हैं, लेकिन कुछ जावा डेवलपर्स "पॉइंटर" शब्द के खिलाफ हैं। जो कुछ। बस पता है कि वस्तु का पता ढेर पर चला जाता है।

इस तरह:

int problems = 99;
String name = "Jay-Z";

a b*7ch aint one!

एक सरणी एक वस्तु है, इसलिए यह ढेर पर भी जाती है। और सरणी में वस्तुओं के बारे में क्या? उन्हें अपना हीप स्पेस मिलता है, और प्रत्येक ऑब्जेक्ट का पता सरणी के अंदर जाता है।

JButton[] marxBros = new JButton[3];
marxBros[0] = new JButton("Groucho");
marxBros[1] = new JButton("Zeppo");
marxBros[2] = new JButton("Harpo");

marx brothers

तो, जब आप कोई विधि कॉल करते हैं तो क्या हो जाता है? यदि आप किसी ऑब्जेक्ट में पास करते हैं, तो आप वास्तव में जो गुजर रहे हैं वह ऑब्जेक्ट का पता है। कुछ पते के "मूल्य" कह सकते हैं, और कुछ कहते हैं कि यह केवल वस्तु का संदर्भ है। यह "संदर्भ" और "मूल्य" समर्थकों के बीच पवित्र युद्ध की उत्पत्ति है। जिसे आप इसे कहते हैं उतना महत्वपूर्ण नहीं है जितना कि आप समझते हैं कि क्या हो रहा है वह वस्तु का पता है।

private static void shout(String name){
    System.out.println("There goes " + name + "!");
}

public static void main(String[] args){
    String hisName = "John J. Jingleheimerschmitz";
    String myName = hisName;
    shout(myName);
}

एक स्ट्रिंग बन जाती है और इसके लिए स्थान ढेर में आवंटित किया जाता है, और स्ट्रिंग पर पता स्टैक पर संग्रहीत किया जाता है और पहचानकर्ता को दिया जाता है hisName, क्योंकि दूसरी स्ट्रिंग का पता पहले जैसा ही है, कोई भी नया स्ट्रिंग नहीं बनाया गया है और कोई नया ढेर स्थान आवंटित नहीं किया गया है, लेकिन स्टैक पर एक नया पहचानकर्ता बनाया गया है। फिर हम कॉल करते हैं shout(): एक नया ढेर फ्रेम बनाया गया है और एक नया पहचानकर्ता है, name पहले से मौजूद स्ट्रिंग का पता बनाया और असाइन किया गया है।

la da di da da da da

तो, मूल्य, संदर्भ? आप "आलू" कहते हैं।


198



हालांकि, आपको एक और जटिल उदाहरण के साथ पालन करना चाहिए था जहां एक फ़ंक्शन एक वैरिएबल को बदलने के लिए प्रतीत होता है जिसके पते पर इसका संदर्भ है। - Brian Peterson
लोग ढेर बनाम ढेर के "वास्तविक मुद्दे के आसपास नृत्य नहीं कर रहे हैं, क्योंकि यह है नहीं वास्तविक मुद्दा यह सबसे अच्छा कार्यान्वयन विवरण है, और सबसे खराब रूप से गलत है। (वस्तुओं के ढेर पर रहने के लिए यह काफी संभव है; Google "बचने का विश्लेषण"। और बड़ी संख्या में वस्तुओं में प्राइमेटिव होते हैं जो शायद नहीं ढेर पर रहते हैं।) असली मुद्दा है ठीक ठीक संदर्भ प्रकारों और मूल्य प्रकारों के बीच अंतर - विशेष रूप से, संदर्भ-प्रकार चर का मान एक संदर्भ है, न कि उस वस्तु को संदर्भित करता है। - cHao
यह जावा में "कार्यान्वयन विस्तार" है, वास्तव में आपको यह दिखाने की आवश्यकता नहीं है कि कोई वस्तु स्मृति में कहाँ रहती है, और वास्तव में यह निर्धारित लगता है कि से बचने उस जानकारी को लीक करना। यह वस्तु को ढेर पर रख सकता है, और आप कभी नहीं जानते। यदि आप परवाह करते हैं, तो आप गलत चीज़ पर ध्यान केंद्रित कर रहे हैं - और इस मामले में, इसका मतलब असली समस्या को अनदेखा करना है। - cHao
और किसी भी तरह से, "प्राइमेटिव्स स्टैक पर जाते हैं" गलत है। आदिम स्थानीय चर ढेर पर जाओ। (अगर उन्हें निश्चित रूप से अनुकूलित नहीं किया गया है।) लेकिन फिर, तो स्थानीय संदर्भ चर करें। और ऑब्जेक्ट के भीतर परिभाषित आदिम सदस्य जहां ऑब्जेक्ट रहता है वहां रहते हैं। - cHao
यहां टिप्पणियों के साथ सहमत हैं। ढेर / ढेर एक पक्ष मुद्दा है, और प्रासंगिक नहीं है। कुछ चर ढेर पर हो सकते हैं, कुछ स्थिर स्मृति (स्थैतिक चर) में हैं, और ढेर पर सभी रहते हैं (सभी ऑब्जेक्ट सदस्य चर)। इन चरों में से कोई भी संदर्भ द्वारा पारित नहीं किया जा सकता है: एक बुलाया विधि से एक तर्क के रूप में पारित चर के मान को बदलने के लिए कभी भी संभव नहीं है। इसलिए, जावा में कोई पास-बाय-रेफरेंस नहीं है। - fishinear


बस विपरीत दिखाने के लिए, निम्न की तुलना करें सी ++ तथा जावा स्निपेट:

सी ++ में: नोट: खराब कोड - मेमोरी लीक!  लेकिन यह बिंदु दर्शाता है।

void cppMethod(int val, int &ref, Dog obj, Dog &objRef, Dog *objPtr, Dog *&objPtrRef)
{
    val = 7; // Modifies the copy
    ref = 7; // Modifies the original variable
    obj.SetName("obj"); // Modifies the copy of Dog passed
    objRef.SetName("objRef"); // Modifies the original Dog passed
    objPtr->SetName("objPtr"); // Modifies the original Dog pointed to 
                               // by the copy of the pointer passed.
    objPtr = new Dog("newObjPtr");  // Modifies the copy of the pointer, 
                                   // leaving the original object alone.
    objPtrRef->SetName("objRefPtr"); // Modifies the original Dog pointed to 
                                    // by the original pointer passed. 
    objPtrRef = new Dog("newObjPtrRef"); // Modifies the original pointer passed
}

int main()
{
    int a = 0;
    int b = 0;
    Dog d0 = Dog("d0");
    Dog d1 = Dog("d1");
    Dog *d2 = new Dog("d2");
    Dog *d3 = new Dog("d3");
    cppMethod(a, b, d0, d1, d2, d3);
    // a is still set to 0
    // b is now set to 7
    // d0 still have name "d0"
    // d1 now has name "objRef"
    // d2 now has name "objPtr"
    // d3 now has name "newObjPtrRef"
}

जावा में,

public static void javaMethod(int val, Dog objPtr)
{
   val = 7; // Modifies the copy
   objPtr.SetName("objPtr") // Modifies the original Dog pointed to 
                            // by the copy of the pointer passed.
   objPtr = new Dog("newObjPtr");  // Modifies the copy of the pointer, 
                                  // leaving the original object alone.
}

public static void main()
{
    int a = 0;
    Dog d0 = new Dog("d0");
    javaMethod(a, d0);
    // a is still set to 0
    // d0 now has name "objPtr"
}

जावा में केवल दो प्रकार के गुजरने हैं: अंतर्निर्मित प्रकारों के मूल्य के आधार पर, और ऑब्जेक्ट प्रकारों के लिए सूचक के मूल्य से।


161



+1 मैं भी जोड़ूंगा Dog **objPtrPtr सी ++ उदाहरण के लिए, इस तरह हम पॉइंटर "पॉइंट्स" को संशोधित कर सकते हैं। - Amro
यह अब तक के सबसे अच्छे उत्तरों में से एक है। यह ज्यादातर अन्य संदर्भ में "संदर्भ के संदर्भ बनाम मूल्य" के अप्रासंगिक अर्थशास्त्र तर्क से बचाता है और इसके बजाय वास्तव में क्या होता है इसके मैकेनिक्स पर चर्चा करता है। मुझे अपने स्वयं के विरोधाभासी या तथ्यात्मक रूप से झूठी सामग्री के कारण अधिकांश अन्य "पास-बाय-वैल्यू" उत्तर देना था, लेकिन इसके बजाय इसे +1 मिलता है। - Aaron


जावा मूल्यों से वस्तुओं के संदर्भ पास करता है।


145



इतना सरल है ! - Ivan Kaloyanov