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


6577

मुझे हमेशा लगा कि जावा पास-बाय-रेफरेंस है

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

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

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


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

119
मैं मूल्यांकन रणनीति लेख में पाई गई शब्दावली का लगातार उपयोग करने की कोशिश करता हूं । यह ध्यान देने योग्य है कि, भले ही शर्तों लेख अंक समुदाय द्वारा काफी भिन्नता है, यह जोर दिया कि के लिए अर्थ विज्ञान call-by-valueऔर call-by-referenceएक बहुत महत्वपूर्ण रास्ता में मतभेद है । (व्यक्तिगत तौर पर मैं का उपयोग करना पसंद call-by-object-sharingसे अधिक इन दिनों call-by-value[-of-the-reference], के रूप में यह एक उच्च स्तर पर अर्थ विज्ञान का वर्णन करता है और साथ कोई विरोध पैदा नहीं करता call-by-valueहै, जो है अंतर्निहित कार्यान्वयन।)

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

29
मुझे लगता है कि भ्रम "संदर्भ द्वारा पारित" बनाम "संदर्भ शब्दार्थ" है। जावा संदर्भ शब्दार्थ के साथ पास-बाय-वैल्यू है।
स्पार्फ

11
@ गुरुत्व, जबकि आप पूरी तरह से सही हैं कि C ++ से आने वाले लोग सहज रूप से "संदर्भ" शब्द के बारे में एक अलग अंतर्ज्ञान सेट करेंगे, मेरा व्यक्तिगत रूप से मानना ​​है कि शरीर "द्वारा" में अधिक दफन है। "पास" में यह भ्रम है कि यह जावा में "पासिंग ए" से बिल्कुल अलग है। C ++ में, हालांकि यह बोलचाल की भाषा में नहीं है। सी ++ में आप कह सकते हैं "एक संदर्भ पारित करना", और यह समझा जाता है कि यह swap(x,y)परीक्षा पास करेगा

जवाबों:


5838

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

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

public static void main(String[] args) {
    Dog aDog = new Dog("Max");
    Dog oldDog = aDog;

    // 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
    aDog == oldDog; // true
}

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फ़ंक्शन में मान नहीं बदला जाता है। यदि यह संदर्भ द्वारा पारित किए गए, तो में वापसी होगी करने के लिए कॉल के बाद ।fooDog "Fifi"aDog.getName()main"Fifi"foo

इसी तरह:

public static void main(String[] args) {
    Dog aDog = new Dog("Max");
    Dog oldDog = aDog;

    foo(aDog);
    // when foo(...) returns, the name of the dog has been changed to "Fifi"
    aDog.getName().equals("Fifi"); // true
    // but it is still the same dog:
    aDog == oldDog; // 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, लेकिन यह है नहीं चर के मूल्य में परिवर्तन करना संभव aDogही।


263
क्या यह आंतरिक विवरण के साथ समस्या को थोड़ा भ्रमित नहीं कर रहा है? 'किसी संदर्भ को पास करने' और 'एक संदर्भ के मूल्य को पास करने' के बीच कोई वैचारिक अंतर नहीं है, यह मानते हुए कि आपका मतलब 'ऑब्जेक्ट के आंतरिक संकेतक का मूल्य' है।
izb

383
लेकिन एक सूक्ष्म अंतर है। पहला उदाहरण देखिए। यदि यह शुद्ध रूप से संदर्भ से गुजरता है, aDog.name "Fifi" होगा। यह नहीं है - आपको जो संदर्भ मिल रहा है वह एक मूल्य संदर्भ है जिसे यदि फ़ंक्शन से बाहर निकलते समय अधिलेखित कर दिया जाएगा।
एरलैंडो

300
@ लोरेंजो: नहीं, जावा में सब कुछ मूल्य से पारित किया गया है। प्रिमिटिव्स वैल्यू द्वारा पास किए जाते हैं और ऑब्जेक्ट रेफरेंस वैल्यू द्वारा पास किए जाते हैं। ऑब्जेक्ट्स को कभी भी एक विधि से पारित नहीं किया जाता है, लेकिन ऑब्जेक्ट हमेशा हीप में होते हैं और केवल ऑब्जेक्ट के लिए एक संदर्भ विधि को पारित किया जाता है।
एस्को लुओटोला

294
ऑब्जेक्ट पासिंग की कल्पना करने के लिए एक अच्छे तरीके से मेरा प्रयास: एक गुब्बारे की कल्पना करें। एक fxn को कॉल करना गुब्बारे को एक दूसरे स्ट्रिंग को टाई करने और fxn को लाइन सौंपने की तरह है। पैरामीटर = नया गुब्बारा () उस तार को काट देगा और एक नया गुब्बारा बनाएगा (लेकिन इसका मूल गुब्बारे पर कोई प्रभाव नहीं है)। पैरामीटर.पॉप () अभी भी इसे पॉप करेगा, क्योंकि यह स्ट्रिंग को एक ही, मूल गुब्बारे का अनुसरण करता है। जावा मूल्य से पास है, लेकिन पारित मूल्य गहरा नहीं है, यह उच्चतम स्तर पर है, अर्थात एक आदिम या एक सूचक। भ्रमित न करें कि एक गहरे पास-पास-मूल्य के साथ जहां ऑब्जेक्ट पूरी तरह से क्लोन किया गया है और पारित किया गया है।
ढाकर

150
क्या भ्रामक है कि वस्तु संदर्भ वास्तव में संकेत हैं। शुरुआत में SUN ने उन्हें पॉइंटर्स कहा। तब मार्केटिंग ने बताया कि "पॉइंटर" एक बुरा शब्द था। लेकिन आप अभी भी NullPointerException में "सही" नामकरण देखते हैं।
प्रो। फाल्कन कॉन्ट्रैक्ट का उल्लंघन

3035

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

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

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

Dog myDog;

है एक कुत्ता; यह वास्तव में एक कुत्ते के लिए एक संकेतक है।

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

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

आप अनिवार्य रूप से विधि के लिए बनाई गई वस्तु का पता दे रहे हैं ।Dogfoo

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

मान लीजिए कि 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 है
    • हम someDog74 को पैरामीटर असाइन करते हैं
  • लाइन "सीसीसी" पर
    • someDog के बाद Dogइसे इंगित किया जाता है ( Dogपते पर ऑब्जेक्ट 74)
    • उस Dog(पते 74 पर) को अपना नाम रोल्फ में बदलने के लिए कहा जाता है
  • फिर, हम लौटते हैं

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

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

वहाँ कुंजी है।

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

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

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

C ++, Ada, पास्कल और अन्य भाषाओं में जो पास-पास-संदर्भ का समर्थन करते हैं, आप वास्तव में उस चर को बदल सकते हैं जो पारित किया गया था।

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

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


164
यही कारण है कि आम परहेज "जावा में संकेत नहीं है" इतना भ्रामक है।
५२ पर बेसका

134
तुम गलत हो, इमो। "यह ध्यान में रखते हुए कि myDog एक पॉइंटर है, न कि एक वास्तविक डॉग, इसका उत्तर है NO। MyDog अभी भी वैल्यू 42 है; यह अभी भी मूल डॉग की ओर इशारा कर रहा है।" myDog का मान 42 है लेकिन इसके नाम तर्क में "AA" लाइन पर "रोवर" की बजाय "Max" लिखा हुआ है।
22zgür

180
इस तरह से इसके बारे में सोचो। किसी के पास ऐन एबोर, एमआई (मेरा गृहनगर, GO BLUE!) का पता कागज की एक पर्ची पर है, जिसे "annArborLocation" कहा जाता है। आप इसे "myDestination" नामक कागज के एक टुकड़े पर कॉपी करते हैं। आप "myDestination" पर ड्राइव कर सकते हैं और एक पेड़ लगा सकते हैं। आपने उस स्थान पर शहर के बारे में कुछ बदल दिया होगा, लेकिन यह LAT / LON को नहीं बदलता है जो या तो कागज पर लिखा गया था। आप "myDestination" पर LAT / LON बदल सकते हैं लेकिन यह "annArborLocation" को नहीं बदलता है। क्या उससे मदद हुई?
स्कॉट स्टैनफील्ड

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

29
@Gevorg - C / C ++ भाषाओं में "पॉइंटर" की अवधारणा नहीं है। अन्य भाषाएँ हैं जो पॉइंटर्स का उपयोग करती हैं लेकिन उसी प्रकार के पॉइंटर्स के हेरफेर की अनुमति नहीं देती हैं जिन्हें C / C ++ अनुमति देता है। जावा में संकेत हैं; वे सिर्फ शरारत के खिलाफ संरक्षित हैं।
स्कॉट स्टैनफ़ील्ड

1739

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


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

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");

    यहां छवि विवरण दर्ज करें

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

    public static void changeReference(Foo a)

    यहां छवि विवरण दर्ज करें

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

    changeReference(f);

    यहां छवि विवरण दर्ज करें

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

    Foo b = new Foo("b");

    यहां छवि विवरण दर्ज करें

  5. a = bसंदर्भ के लिए एक नया काम में आता है a, नहीं f , वस्तु जिसका इसकी विशेषता है की "b"

    यहां छवि विवरण दर्ज करें

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

    यहां छवि विवरण दर्ज करें

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

    यहां छवि विवरण दर्ज करें

मुझे उम्मीद है कि अब आप समझ गए होंगे कि जावा में तर्क के काम करने के तरीके कैसे गुजरते हैं :)


82
+1 अच्छा सामान। अच्छे चित्र। मुझे यहाँ एक अच्छा रसीला पृष्ठ भी मिला, यहाँ adp-gmbh.ch/php/pass_by_reference.html ठीक है मैं मानता हूँ कि यह PHP में लिखा गया है, लेकिन यह उस अंतर को समझने का सिद्धांत है जो मुझे लगता है कि महत्वपूर्ण है (और कैसे उस अंतर में हेरफेर किया जाए? आपकी ज़रूरतें)।
डेवएम

5
@ Eng.Fouad यह एक अच्छी व्याख्या है, लेकिन अगर aएक ही वस्तु की ओर इशारा किया जाता है f(और वस्तु के fअंक की अपनी प्रति कभी नहीं मिलती है), तो उपयोग की गई वस्तु में कोई भी बदलाव अस्वस्थ aको संशोधित करना चाहिए f(क्योंकि वे दोनों एक ही वस्तु के साथ काम कर रहे हैं ), तो कुछ बिंदु पर वस्तु बिंदुओं की aअपनी प्रति प्राप्त करनी चाहिए f
19x पर 0x6C38

14
@MrD जब 'a' एक ही ऑब्जेक्ट 'f' की ओर इशारा करता है, तो 'ऑब्जेक्ट' के माध्यम से उस ऑब्जेक्ट में किए गए किसी भी परिवर्तन को 'f', BUT IT DID NOT CHANGE 'f' के माध्यम से भी देखा जा सकता है। 'f' अभी भी उसी वस्तु की ओर इशारा करता है। आप वस्तु को पूरी तरह से बदल सकते हैं, लेकिन आप कभी भी नहीं बदल सकते हैं जो 'च' को इंगित करता है। यह मूलभूत मुद्दा है कि किसी कारण से कुछ लोग बस समझ नहीं सकते हैं।
माइक ब्रौन

@ मायके बरौन ... क्या? अब आपने मुझे भ्रमित कर दिया है: एस। क्या आपने सिर्फ 6. और 7. शो के विपरीत नहीं लिखा है?
ईविल वॉशिंग मशीन

6
यह सबसे अच्छा स्पष्टीकरण है जो मैंने पाया है। वैसे, मूल स्थिति के बारे में क्या? उदाहरण के लिए, तर्क के लिए एक int प्रकार की आवश्यकता होती है, क्या यह अभी भी तर्क के लिए एक अंतर चर की प्रति पारित करता है?
एलेनवांग

732

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

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

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

  • छात्र : मास्टर, क्या इसका मतलब यह है कि जावा पास-बाय-रेफरेंस है?
  • मास्टर : ग्रासहॉपर, नहीं।

अब सोचें कि एक वस्तु का संदर्भ / चर क्या करता है / है:

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

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

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 पर टिप्पणी की जाँच करें
  • एक विधि स्थानीय चर - एक और ReferenceToTheSamePersonObject - बनाया जाता है और फिर लाइन # 1 में जादू आता है:
    • चर / संदर्भ व्यक्ति को बिट-बाय-कॉपी किया जाता है और फ़ंक्शन के अंदर किसी अन्य ReferenceToTheSamePersonObject को पास किया जाता है।
    • व्यक्ति के कोई नए उदाहरण नहीं बनाए गए हैं।
    • " व्यक्ति " और " otherReferenceToTheSamePersonObject " दोनों का मूल्य 3bad086a समान है।
    • इस कोशिश मत करो, लेकिन व्यक्ति == एक और संदर्भप्रतिवाद .amePersonObject सच होगा।
    • दोनों चरों के संदर्भ की गुणात्मक प्रतियां हैं और वे दोनों एक ही व्यक्ति वस्तु, समान वस्तु हीप और न कि एक प्रतिरूप को संदर्भित करते हैं।

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

मान से पास करें

ध्यान दें कि एक औरReferenceToTheSamePersonObject तीरों को वस्तु की ओर निर्देशित किया जाता है न कि परिवर्तनशील व्यक्ति की ओर!

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

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

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

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

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


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


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


5
क्या आपका मतलब पॉइंटर्स से है? .. अगर मैं इसे सही तरीके से प्राप्त करता हूं public void foo(Car car){ ... }, तो carयह लोकल है fooऔर इसमें ऑब्जेक्ट का हीप लोकेशन है? इसलिए अगर मैं इसके carमूल्य को बदल दूं car = new Car(), तो यह ढेर के विभिन्न ऑब्जेक्ट को इंगित करेगा? और अगर मैं carसंपत्ति के मूल्य को बदल देता हूं car.Color = "Red", तो बताई गई ढेर की वस्तु को carसंशोधित किया जाएगा। इसके अलावा, यह C # में समान है? कृपया उत्तर दें! धन्यवाद!
dpp

11
@domanokz तुम मुझे मार रहे हो, कृपया उस शब्द को दोबारा मत कहो! ;) ध्यान दें कि मैं इस प्रश्न का उत्तर 'संदर्भ' के बिना भी कह सकता था। यह एक शब्दावली का मुद्दा है और 'p इसे बदतर बना देता है। दुर्भाग्य से इस पर मेरे और स्कॉट के अलग-अलग विचार हैं। मुझे लगता है कि आपको जावा में यह कैसे काम करता है, अब आप इसे पास-वैल्यू, बाय-ऑब्जेक्ट-शेयरिंग, बाय-कॉपी-ऑफ-द-वेरिएबल-वैल्यू, या कुछ और के साथ आने के लिए स्वतंत्र महसूस कर सकते हैं! मैं वास्तव में तब तक परवाह नहीं करता जब तक आपको यह नहीं मिला कि यह कैसे काम करता है और वस्तु के एक चर में क्या है: बस एक PO बॉक्स पता! ;)
मार्सेलस वालेस

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

3
तो सैद्धांतिक लाइन # 9 पर छोड़ दें, System.out.println(person.getName());क्या दिखाई देगा? "टॉम" या "जेरी"? यह आखिरी चीज है जो मुझे इस भ्रम को दूर करने में मदद करेगी।
TheBrenny

1
" संदर्भ का मूल्य " वह है जो आखिरकार मुझे समझाता है।
अलेक्जेंडर शुबर्ट

689

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

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

तो, जब एक विधि बुला

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

इसलिए यदि आपके पास है doSomething(foo)और public void doSomething(Foo foo) { .. }दो Foos ने संदर्भों की प्रतिलिपि बनाई है जो समान वस्तुओं की ओर इशारा करते हैं।

स्वाभाविक रूप से, किसी वस्तु के संदर्भ के मान से गुजरना बहुत पसंद होता है (और व्यवहार से अप्रभेद्य है) किसी वस्तु को संदर्भ के साथ पारित करना।


7
चूंकि आदिमों के मूल्य अपरिवर्तनीय हैं (जैसे स्ट्रिंग), दो मामलों के बीच का अंतर वास्तव में प्रासंगिक नहीं है।
पाओलो एबरमन

4
बिल्कुल सही। सभी के लिए आप अवलोकन योग्य जेवीएम व्यवहार के माध्यम से बता सकते हैं, आदिम को संदर्भ द्वारा पारित किया जा सकता है और ढेर पर रह सकता है। वे नहीं करते हैं, लेकिन यह वास्तव में किसी भी तरह से देखने योग्य नहीं है।
गुरुत्वाकर्षण

6
आदिम अपरिवर्तनीय हैं? जावा 7 में नया क्या है?
user85421

4
संकेत अपरिवर्तनीय हैं, सामान्य रूप से प्राइमिटिव परस्पर हैं। स्ट्रिंग भी एक आदिम नहीं है, यह एक वस्तु है। इसके अलावा, स्ट्रिंग की अंतर्निहित संरचना एक परिवर्तनशील सरणी है। इसके बारे में एकमात्र अपरिवर्तनीय बात लंबाई है, जो सरणियों की अंतर्निहित प्रकृति है।
किंगफ्रिटो_5005

3
यह तर्क के बड़े पैमाने पर शब्दार्थ प्रकृति की ओर इशारा करते हुए एक और जवाब है। इस उत्तर में दी गई संदर्भ की परिभाषा जावा को "पास-दर-संदर्भ" बनाएगी। लेखक अनिवार्य रूप से अंतिम पैराग्राफ में यह कहते हुए स्वीकार करता है कि यह "पास-बाय-रेफरेंस" से "व्यवहार में अविभाज्य" है। मुझे संदेह है कि ओपी जावा कार्यान्वयन को समझने की इच्छा के कारण पूछ रहा है, लेकिन यह समझने के लिए कि जावा का सही उपयोग कैसे करें। यदि यह व्यवहार में अप्रभेद्य था, तो देखभाल करने का कोई मतलब नहीं होगा और यहां तक ​​कि इसके बारे में सोचना समय की बर्बादी होगी।
लॉडूविज्क

331

जावा मान द्वारा संदर्भ देता है।

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


27
लेकिन जो चीज बार-बार मिलती रहती है "आप तर्कों में पारित वस्तुओं के मूल्य को बदल नहीं सकते हैं" स्पष्ट रूप से गलत है। हो सकता है कि आप उन्हें किसी भिन्न ऑब्जेक्ट का संदर्भ देने में सक्षम न हों, लेकिन आप उनके तरीकों को कॉल करके उनकी सामग्री को बदल सकते हैं। IMO का अर्थ है कि आप संदर्भों के सभी लाभों को खो देते हैं, और कोई अतिरिक्त गारंटी नहीं प्राप्त करते हैं।
टिममम

34
मैंने कभी नहीं कहा "आप तर्कों में पारित वस्तुओं के मूल्य को बदल नहीं सकते हैं"। मैं कहूंगा "आप एक विधि तर्क के रूप में पारित वस्तु संदर्भ के मूल्य को बदल नहीं सकते हैं", जो जावा भाषा के बारे में एक सच्चा कथन है। जाहिर है आप वस्तु की स्थिति को बदल सकते हैं (जब तक यह अपरिवर्तनीय नहीं है)।
ScArcher2

20
ध्यान रखें कि आप वास्तव में जावा में वस्तुओं को पारित नहीं कर सकते हैं; वस्तुएं ढेर पर रहती हैं। ऑब्जेक्ट्स के पॉइंटर्स को पास किया जा सकता है (जिसे स्टैक फ्रेम पर कॉपी किया जाता है)। तो आप कभी भी पास-इन वैल्यू (पॉइंटर) को नहीं बदलते हैं, लेकिन आप इसे फॉलो करने के लिए स्वतंत्र हैं और जिस चीज को इंगित करते हैं उसे हीप में बदलें। वह पास-बाय-वैल्यू है।
स्कॉट स्टैनफ़ील्ड

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

3
जावा किसी ऑब्जेक्ट को पास नहीं करता है, यह पॉइंटर को ऑब्जेक्ट के मान से गुजरता है। यह एक नए चर में मूल वस्तु के स्मृति स्थान के लिए एक नया सूचक बनाता है। यदि आप इस पॉइंटर वैरिएबल के मान (मेमोरी एड्रेस को इंगित करते हैं) को किसी विधि में बदलते हैं, तो मेथड कॉलर में उपयोग किया गया ओरिजनल पॉइंटर अनमॉडिफाइड रहता है। यदि आप पैरामीटर को संदर्भ कह रहे हैं, तो यह तथ्य कि यह मूल संदर्भ की एक प्रति है, न कि मूल संदर्भ ही ऐसा है कि वस्तु के दो संदर्भ अब हैं इसका मतलब है कि यह पास-बाय-वैल्यू है
theferrit32

238

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

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

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

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

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

इसमें परिणाम:

ढेर पर आदिम

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

इस तरह:

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

ab * 7ch aint एक!

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

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

मार्क्स भाइयों

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

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पहले से मौजूद स्ट्रिंग का पता बनाया और सौंपा जाता है।

ला दा दी दा दा दा दा

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


7
हालाँकि, आपको अधिक जटिल उदाहरण के साथ पालन करना चाहिए जहां एक फ़ंक्शन एक चर को बदलता है जिसके पते पर इसका संदर्भ है।
ब्रायन पीटरसन

34
लोग ढेर ढेर बनाम की 'असली समस्या के नृत्य ", क्योंकि वह है नहीं कर रहे हैं नहीं असली मुद्दा। यह सबसे अच्छा में एक कार्यान्वयन विवरण है, और सबसे खराब गलत है। (यह वस्तुओं के ढेर पर रहने के लिए बहुत संभव है; Google "एस्केप एनालिसिस"। और बड़ी संख्या में ऑब्जेक्ट में प्राइमिटिव होते हैं जो संभवतः स्टैक पर नहीं रहते हैं।) असली मुद्दा बिल्कुल संदर्भ प्रकारों और मूल्य प्रकारों के बीच का अंतर है। - विशेष रूप से, कि एक संदर्भ-प्रकार चर का मान एक संदर्भ है, न कि वह वस्तु जिसे वह संदर्भित करता है।
cHao

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

10
और किसी भी तरह से, "आदिम ढेर पर चलते हैं" गलत है। आदिम स्थानीय चर स्टैक पर चलते हैं। (यदि उन्हें निश्चित रूप से अनुकूलित नहीं किया गया है।) लेकिन फिर, इसलिए स्थानीय संदर्भ चर बनाएं । और एक वस्तु के भीतर परिभाषित आदिम सदस्य रहते हैं जहाँ वस्तु रहती है।
cHao

9
यहां टिप्पणियों से सहमत हों। ढेर / ढेर एक पक्ष मुद्दा है, और प्रासंगिक नहीं है। कुछ चर स्टैक पर हो सकते हैं, कुछ स्टैटिक मेमोरी (स्थैतिक चर) में होते हैं, और ढेर पर रहते हैं (सभी ऑब्जेक्ट सदस्य चर)। इन चरों में से किसी को भी संदर्भ के द्वारा पारित किया जा सकता है: किसी विधि से किसी तर्क के रूप में पारित होने वाले चर के मान को बदलना संभव नहीं है। इसलिए, जावा में कोई पास-बाय-रेफरेंस नहीं है।
फिशिनियर

195

इसके विपरीत दिखाने के लिए, निम्नलिखित C ++ और Java स्निपेट की तुलना करें :

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

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"
}

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


7
+1 मैं Dog **objPtrPtrC ++ उदाहरण में भी जोड़ूंगा, इस तरह से हम संकेत कर सकते हैं कि सूचक "अंक" को क्या कहता है।
अमरो

1
लेकिन यह जावा में दिए गए प्रश्न का उत्तर नहीं देता है। तथ्य की बात के रूप में, जावा की विधि में सब कुछ पास बाय वैल्यू है, इससे ज्यादा कुछ नहीं।
9

2
यह छूट सिर्फ यह साबित करती है कि जावा सी में सूचक के बहुत बराबर का उपयोग करता है? C में मान से पास होने पर मूल रूप से केवल पढ़ा जाता है? अंत में, यह पूरा धागा समझ से बाहर है
amdev


166

मूल रूप से, पुनर्मूल्यांकन वस्तु पैरामीटर तर्क को प्रभावित नहीं करता है, उदाहरण के लिए,

private void foo(Object bar) {
    bar = null;
}

public static void main(String[] args) {
    String baz = "Hah!";
    foo(baz);
    System.out.println(baz);
}

के "Hah!"बजाय बाहर प्रिंट होगा null। इसका कारण यह है क्योंकि काम barके मूल्य की एक प्रति है baz, जो कि केवल एक संदर्भ है "Hah!"। यदि यह वास्तविक संदर्भ ही होता, तो fooफिर bazसे परिभाषित किया गया होता null


8
मैं बल्कि कहूंगा कि बार संदर्भ बाज (या बाज उर्फ) की एक प्रति है, जो शुरू में एक ही वस्तु को इंगित करता है।
मैक्सजूम

स्ट्रिंग वर्ग और अन्य सभी वर्गों के बीच थोड़ा सा अंतर नहीं है?
मेहदी करमोसली

152

मैं विश्वास नहीं कर सकता कि किसी ने अभी तक बारबरा लिस्कॉव का उल्लेख नहीं किया है। जब वह 1974 में CLU बनाया गया है, वह इस एक ही शब्दावली समस्या में पड़ गए, और वह अवधि का आविष्कार साझा करने से कॉल (भी रूप में जाना जाता वस्तु के बंटवारे से कॉल और वस्तु से कॉल मूल्य से) "कॉल के इस विशेष मामले के लिए जहां मूल्य है संदर्भ"।


3
मुझे नामकरण में यह अंतर पसंद है। यह दुर्भाग्यपूर्ण है कि जावा वस्तुओं के लिए साझा करके कॉल का समर्थन करता है, लेकिन मूल्य से कॉल नहीं करता है (जैसा कि C ++)। जावा केवल आदिम डेटा प्रकारों के लिए मूल्य से कॉल का समर्थन करता है और समग्र डेटा प्रकारों के लिए नहीं।
डेरेक महार

2
मुझे वास्तव में नहीं लगता कि हमें एक अतिरिक्त शब्द की आवश्यकता है - यह एक विशिष्ट प्रकार के मूल्य के लिए बस पास-पास-मूल्य है। "आदिम द्वारा कॉल" जोड़ना कोई स्पष्टीकरण जोड़ देगा?
स्कॉट स्टैनफ़ील्ड


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

1
@ संजीव: कॉल-बाय-ऑब्जेक्ट-शेयरिंग पास-बाय-वैल्यू का एक विशेष मामला है। हालाँकि, बहुत से लोग तर्क देते हैं कि जावा (और इसी तरह की भाषाएं जैसे पायथन, रूबी, ईसीएमएस्क्रिप्ट, स्मॉलटाक) पास-बाय-रेफरेंस हैं। मैं इसे पारित-दर-मूल्य भी कॉल करने के लिए पसंद करते हैं, लेकिन कॉल-दर-वस्तु के बंटवारे एक उचित शब्द है कि यहां तक कि लोग हैं, जो तर्क है कि यह है कि हो रहा है नहीं पारित-दर-मूल्य के लिए सहमत कर सकते हैं।
जोर्ज डब्ल्यू मित्तग

119

इस मामले की जड़ यह है कि शब्द है संदर्भ अभिव्यक्ति में साधन कुछ शब्द का सामान्य अर्थ से पूरी तरह से अलग "संदर्भ द्वारा पारित" संदर्भ जावा में।

जावा में आम तौर पर संदर्भ आ मतलब है एक वस्तु के संदर्भ में । लेकिन प्रोग्रामिंग भाषा सिद्धांत से संदर्भ / मूल्य से गुजरने वाले तकनीकी शब्द चर को पकड़े हुए मेमोरी सेल के संदर्भ में बात कर रहे हैं , जो कुछ पूरी तरह से अलग है।


7
@ जॉर्ज - फिर "NullPointerException" क्या है?
हॉट लिप्स

5
@Hot: दुर्भाग्य से नामित एक अपवाद के रूप में जावा एक स्पष्ट शब्दावली पर बसने से पहले। C # में शब्दार्थ समतुल्य अपवाद NullReferenceException कहलाता है।
जैक्सबी

4
यह मुझे हमेशा लगता है कि जावा शब्दावली में "संदर्भ" का उपयोग समझ को बाधित करने वाला एक प्रभाव है।
हॉट लिप्स

मैंने इन तथाकथित "पॉइंटर्स टू ऑब्जेक्ट्स" को "ऑब्जेक्ट को हैंडल" के रूप में कॉल करना सीखा। इससे अस्पष्टता कम हुई।
मोरोंक्रेसीओनज़

86

जावा में सब कुछ संदर्भ है, इसलिए जब आपके पास कुछ ऐसा हो: Point pnt1 = new Point(0,0);जावा निम्नलिखित करता है:

  1. नई प्वाइंट ऑब्जेक्ट बनाता है
  2. नए बिंदु संदर्भ बनाता है और पहले बनाए गए बिंदु वस्तु पर उस बिंदु (संदर्भ) को संदर्भित करता है
  3. यहां से, पॉइंट ऑब्जेक्ट लाइफ के माध्यम से, आप pnt1 संदर्भ के माध्यम से उस ऑब्जेक्ट तक पहुंचेंगे। तो हम कह सकते हैं कि जावा में आप इसके संदर्भ के माध्यम से वस्तु में हेरफेर करते हैं।

यहां छवि विवरण दर्ज करें

जावा संदर्भ द्वारा विधि तर्क पारित नहीं करता है; यह उन्हें मूल्य से गुजरता है।मैं इस साइट से उदाहरण का उपयोग करूंगा :

public static void tricky(Point arg1, Point arg2) {
  arg1.x = 100;
  arg1.y = 100;
  Point temp = arg1;
  arg1 = arg2;
  arg2 = temp;
}
public static void main(String [] args) {
  Point pnt1 = new Point(0,0);
  Point pnt2 = new Point(0,0);
  System.out.println("X1: " + pnt1.x + " Y1: " +pnt1.y); 
  System.out.println("X2: " + pnt2.x + " Y2: " +pnt2.y);
  System.out.println(" ");
  tricky(pnt1,pnt2);
  System.out.println("X1: " + pnt1.x + " Y1:" + pnt1.y); 
  System.out.println("X2: " + pnt2.x + " Y2: " +pnt2.y);  
}

कार्यक्रम का प्रवाह:

Point pnt1 = new Point(0,0);
Point pnt2 = new Point(0,0);

दो अलग-अलग पॉइंट ऑब्जेक्ट बनाना जिसमें दो अलग-अलग संदर्भ जुड़े हैं। यहां छवि विवरण दर्ज करें

System.out.println("X1: " + pnt1.x + " Y1: " +pnt1.y); 
System.out.println("X2: " + pnt2.x + " Y2: " +pnt2.y);
System.out.println(" ");

जैसा कि अपेक्षित आउटपुट होगा:

X1: 0     Y1: 0
X2: 0     Y2: 0

इस लाइन पर 'पास-बाय-वैल्यू' नाटक में जाता है ...

tricky(pnt1,pnt2);           public void tricky(Point arg1, Point arg2);

संदर्भ pnt1और ट्रिकी विधि के लिए मूल्य द्वारा पारित किएpnt2 जाते हैं , जिसका अर्थ है कि अब आपका संदर्भ है और उनके नाम और .So और अंक हैंpnt1pnt2copiesarg1arg2pnt1arg1 उसी ऑब्जेक्ट को करता है। (उसी के लिए pnt2और arg2) यहां छवि विवरण दर्ज करें

में trickyविधि:

 arg1.x = 100;
 arg1.y = 100;

यहां छवि विवरण दर्ज करें

इसके बाद में trickyविधि

Point temp = arg1;
arg1 = arg2;
arg2 = temp;

यहाँ, आप पहले नया बनाने tempप्वाइंट संदर्भ जो होगा इंगित की तरह एक ही जगह पर arg1संदर्भ। फिर आप संदर्भ की तरह उसी स्थान arg1पर इंगित करने के लिए संदर्भ स्थानांतरित करते हैं arg2। अंत में उसी जगह की ओर इशाराarg2 करेंगे जैसेtemp

यहां छवि विवरण दर्ज करें

यहाँ से के दायरे trickyविधि चला गया है और आप संदर्भ के लिए किसी भी अधिक पहुँच नहीं है: arg1, arg2, tempलेकिन महत्वपूर्ण बात यह है कि जब आप 'जीवन में' इन संदर्भों के साथ सब कुछ करते हैं, तो वे उस वस्तु को स्थायी रूप से प्रभावित करेंगे जिस पर वे इशारा करते हैं।

इसलिए निष्पादन विधि के बाद tricky, जब आप वापस आते हैं main, तो आपके पास यह स्थिति होती है: यहां छवि विवरण दर्ज करें

तो अब, पूरी तरह से कार्यक्रम का निष्पादन होगा:

X1: 0         Y1: 0
X2: 0         Y2: 0
X1: 100       Y1: 100
X2: 0         Y2: 0

7
जावा में जब आप कहते हैं कि "जावा में सब कुछ संदर्भ है" तो आपका मतलब है कि सभी वस्तुओं को संदर्भ द्वारा पारित किया जाता है। आदिम डेटा प्रकार संदर्भ द्वारा पारित नहीं किए जाते हैं।
एरिक

मैं मुख्य विधि में स्वैप किए गए मूल्य को प्रिंट करने में सक्षम हूं। ट्रिकी विधि में, निम्न कथन को जोड़ें arg1.x = 1; arg1.y = 1; arg2.x = 2; arg2.y = 2;, जैसे कि arg1 अब pnt2 रिफ्रेंस को पकड़े हुए और arg2 अब pnt1 संदर्भ को पकड़े हुए है, इसलिए, इसका मुद्रणX1: 2 Y1: 2 X2: 1 Y2: 1
शाहिद गफ़ूर

85

जावा हमेशा मान से पास होता है, संदर्भ से नहीं

सबसे पहले, हमें यह समझने की आवश्यकता है कि संदर्भ द्वारा मान और पास क्या हैं।

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

संदर्भ द्वारा पास (जिसे पता द्वारा पास भी कहा जाता है) का अर्थ है कि वास्तविक पैरामीटर के पते की एक प्रति संग्रहीत है

कभी-कभी जावा संदर्भ द्वारा पास का भ्रम दे सकता है। आइए नीचे दिए गए उदाहरण का उपयोग करके देखें कि यह कैसे काम करता है:

public class PassByValue {
    public static void main(String[] args) {
        Test t = new Test();
        t.name = "initialvalue";
        new PassByValue().changeValue(t);
        System.out.println(t.name);
    }

    public void changeValue(Test f) {
        f.name = "changevalue";
    }
}

class Test {
    String name;
}

इस कार्यक्रम का आउटपुट है:

changevalue

आइए कदम से कदम समझते हैं:

Test t = new Test();

जैसा कि हम सभी जानते हैं कि यह ढेर में एक वस्तु बनाएगा और संदर्भ मान को वापस t पर लौटाएगा। उदाहरण के लिए, मान लीजिए कि t का मान है 0x100234(हम वास्तविक JVM आंतरिक मूल्य नहीं जानते हैं, यह सिर्फ एक उदाहरण है)।

पहला चित्रण

new PassByValue().changeValue(t);

फ़ंक्शन से संदर्भ टी पास करते समय यह सीधे ऑब्जेक्ट परीक्षण के वास्तविक संदर्भ मूल्य को पारित नहीं करेगा, लेकिन यह टी की एक प्रति बनाएगा और फिर फ़ंक्शन को पास करेगा। चूंकि यह मूल्य से गुजर रहा है , यह इसके वास्तविक संदर्भ के बजाय चर की एक प्रति से गुजरता है। चूंकि हमने कहा था कि t का मान था 0x100234, t और f दोनों का मान समान होगा और इसलिए वे एक ही वस्तु की ओर इशारा करेंगे।

दूसरा चित्रण

यदि आप संदर्भ च का उपयोग करके फ़ंक्शन में कुछ भी बदलते हैं तो यह ऑब्जेक्ट की मौजूदा सामग्री को संशोधित करेगा। यही कारण है कि हमें आउटपुट मिला changevalue, जिसे फ़ंक्शन में अपडेट किया गया है।

इसे और अधिक स्पष्ट रूप से समझने के लिए, निम्नलिखित उदाहरण पर विचार करें:

public class PassByValue {
    public static void main(String[] args) {
        Test t = new Test();
        t.name = "initialvalue";
        new PassByValue().changeRefence(t);
        System.out.println(t.name);
    }

    public void changeRefence(Test f) {
        f = null;
    }
}

class Test {
    String name;
}

क्या यह फेंक देगा NullPointerException? नहीं, क्योंकि यह केवल संदर्भ की एक प्रति है। संदर्भ से गुजरने के मामले में, यह एक फेंक सकता है NullPointerException, जैसा कि नीचे देखा गया है:

तीसरा चित्रण

उम्मीद है कि इससे मदद मिलेगी।


71

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

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

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

कोर के नीचे यह किसी भी भाषा में किसी भी चीज का संदर्भ दिए बिना उसका प्रतिनिधित्व करने के लिए तकनीकी रूप से असंभव है (जब यह तुरंत एक मूल्य बन जाता है)।

मान लें कि हमारे पास एक वेरिएबल Foo है, इसका स्थान मेमोरी में 47 वें बाइट पर है और इसका मान 5. है। हमारे पास एक और वैरिएबल Ref2Foo है जो कि मेमोरी में 223 वें बाइट पर है, और इसका मान 47 होगा। यह Ref2Foo एक तकनीकी वैरिएबल हो सकता है। , कार्यक्रम द्वारा स्पष्ट रूप से नहीं बनाया गया। यदि आप किसी अन्य जानकारी के बिना सिर्फ 5 और 47 को देखते हैं, तो आपको सिर्फ दो मूल्य दिखाई देंगे । यदि आप उन्हें संदर्भ के रूप में उपयोग करते हैं तो 5हमें यात्रा करने के लिए पहुंचना होगा :

(Name)[Location] -> [Value at the Location]
---------------------
(Ref2Foo)[223]  -> 47
(Foo)[47]       -> 5

इस तरह से जंप-टेबल काम करते हैं।

अगर हम फू के मूल्य के साथ एक विधि / फ़ंक्शन / प्रक्रिया को कॉल करना चाहते हैं, तो चर को विधि में पारित करने के लिए कुछ संभव तरीके हैं, जो भाषा और इसके कई विधि आह्वान मोड पर निर्भर करता है:

  1. 5 सीपीयू रजिस्टर (यानी। EAX) में से एक में कॉपी हो जाता है।
  2. 5 ढेर में PUSHd हो जाता है।
  3. 47 एक CPU रजिस्टर में कॉपी हो जाती है
  4. 47 ढेर करने के लिए।
  5. 223 CPU रजिस्टरों में से एक में कॉपी हो जाता है।
  6. 223 स्टैक को PUSHd मिलता है।

एक मूल्य से ऊपर के हर मामले में - एक मौजूदा मूल्य की एक प्रति बनाई गई है - अब इसे संभालने के लिए प्राप्त करने की विधि तक है। जब आप विधि के अंदर "फू" लिखते हैं, तो इसे या तो EAX से पढ़ा जाता है, या स्वचालित रूप से dereferenced , या डबल dereferenced, प्रक्रिया इस बात पर निर्भर करती है कि भाषा कैसे काम करती है और / या किस प्रकार का फू निर्धारित करता है। यह डेवलपर से छिपा हुआ है जब तक कि वह dereferencing प्रक्रिया को समाप्त नहीं करता है। इसलिए एक संदर्भ का प्रतिनिधित्व करते समय एक मूल्य है , क्योंकि एक संदर्भ एक मूल्य है जिसे संसाधित किया जाना है (भाषा स्तर पर)।

अब हमने फू को विधि में पास कर दिया है:

  • यदि आप फू को बदलते हैं तो 1. और 2.Foo = 9 ) को यह केवल स्थानीय दायरे को प्रभावित करता है क्योंकि आपके पास मूल्य की एक प्रति है। विधि के अंदर से हम यह भी निर्धारित नहीं कर सकते हैं कि मूल फू कहां स्थित है।
  • यदि आप डिफ़ॉल्ट भाषा के निर्माणों का उपयोग करते हैं और फू ( Foo = 11) को बदलते हैं, तो यह 3. और 4. विश्व स्तर पर फू को बदल सकता है (भाषा पर निर्भर करता है, यानी जावा या पास्कल के procedure findMin(x, y, z: integer;var m की तरह : integer);)। हालाँकि, यदि भाषा आपको अनुमेय प्रक्रिया को दरकिनार करने की अनुमति देती है, तो आप बदल सकते हैं 47, कह सकते हैं 49। यदि आप इसे पढ़ते हैं, तो उस समय फू को बदल दिया गया लगता है, क्योंकि आपने स्थानीय सूचक को इसे बदल दिया है। और यदि आप विधि के अंदर इस फू को संशोधित करने के लिए थे ( Foo = 12तो आप शायद कार्यक्रम के निष्पादन (aka। Segfault) को समाप्त कर देंगे क्योंकि आप अपेक्षा से अलग मेमोरी में लिखेंगे, आप निष्पादन योग्य रखने के लिए नियत क्षेत्र को भी संशोधित कर सकते हैं। प्रोग्राम और इसे लिखने से रनिंग कोड संशोधित हो जाएगा (फू अब नहीं है47 )। BUT फू का मान47विश्व स्तर पर नहीं बदला, केवल एक विधि के अंदर, क्योंकि 47विधि के लिए एक प्रति भी थी।
  • मामले में 5. और 6. यदि आप 223विधि के अंदर संशोधित करते हैं तो यह 3. या 4. के रूप में एक ही तबाही बनाता है (एक सूचक, अब खराब मान की ओर इशारा करता है, जो फिर से एक सूचक के रूप में उपयोग किया जाता है) लेकिन यह अभी भी एक स्थानीय है समस्या, 223 की नकल थी । हालाँकि, अगर आप डिरेफेरेंस Ref2Foo(यानी 223) करने में सक्षम हैं, तो बताए गए मान को संशोधित करने और संशोधित करने के लिए पहुंचें 47, कहेंगे 49, यह विश्व स्तर पर फू को प्रभावित करेगा , क्योंकि इस मामले में विधियों की एक प्रति मिली है, 223 लेकिन संदर्भित 47केवल एक बार मौजूद है, और इसे बदल रहा है करने के लिए 49हर नेतृत्व करेंगे Ref2Fooएक गलत मान के लिए डबल-dereferencing।

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

सख्त पास-बाय-वैल्यू भी बेकार है, इसका मतलब यह होगा कि हर बार जब हम एरी को तर्क के साथ एक विधि कहते हैं, तो 100 Mbyte सरणी को कॉपी करना होगा, इसलिए Java को सख्ती से पास-बाय-वैल्यू नहीं किया जा सकता है। प्रत्येक भाषा इस विशाल सरणी (एक मान के रूप में) के संदर्भ को पारित करेगी और या तो कॉपी-ऑन-राइट तंत्र को नियोजित करेगी यदि उस सरणी को स्थानीय रूप से विधि के अंदर बदला जा सकता है या विधि को (जैसा कि जावा करता है) विश्व स्तर पर सरणी को संशोधित करने की अनुमति देता है कॉलर का दृष्टिकोण) और कुछ भाषाओं के संदर्भ के मूल्य को संशोधित करने की अनुमति देता है।

तो संक्षेप में और जावा की अपनी शब्दावली में, जावा पास-बाय-वैल्यू है जहां मूल्य हो सकता है: या तो एक वास्तविक मूल्य या एक मूल्य जो एक संदर्भ का प्रतिनिधित्व है ।


1
पास-बाई-रेफ़रेंस वाली भाषा में, जो चीज़ पास की जाती है (संदर्भ) अल्पकालिक; प्राप्तकर्ता इसे कॉपी करने के लिए "माना" नहीं जाता है। जावा में, एक सरणी पास करना एक "ऑब्जेक्ट आइडेंटिफ़ायर" है - कागज की एक पर्ची के बराबर है जो "ऑब्जेक्ट # 24601" कहता है, जब निर्मित 24601 वां ऑब्जेक्ट एक सरणी था। प्राप्तकर्ता "ऑब्जेक्ट # 24601" को कहीं भी कॉपी कर सकता है, और कागज की एक पर्ची के साथ कोई भी कह सकता है कि "ऑब्जेक्ट # 24601" किसी भी एरे तत्वों के साथ कुछ भी कर सकता है। बिट्स के पैटर्न को वास्तव में "ऑब्जेक्ट # 24601" नहीं कहा जाएगा, लेकिन ...
17

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

दरअसल, पास्कल में आप प्रत्येक चर का पता प्राप्त कर सकते हैं, यह पास-पास-संदर्भ या स्थानीय रूप से कॉपी किया जा सकता है, addrक्या यह अप्रमाणित है, @यह प्रकार के साथ करता है, और आप बाद में संदर्भित चर को संशोधित कर सकते हैं (स्थानीय रूप से कॉपी किए गए लोगों को छोड़कर)। लेकिन मैं इस बात को नहीं देखता कि आप ऐसा क्यों करेंगे। आपके उदाहरण में कागज की पर्ची (ऑब्जेक्ट # 24601) एक संदर्भ है, इसका उद्देश्य स्मृति में सरणी को खोजने में मदद करना है, इसमें अपने आप में कोई सरणी डेटा शामिल नहीं है। यदि आप अपने कार्यक्रम को पुनः आरंभ करते हैं, तो समान सरणी को एक अलग ऑब्जेक्ट-आईडी मिल सकता है, भले ही उसकी सामग्री उसी तरह की हो जो पिछले भाग में रही हो।
karatedog

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

... जो अतिक्रमण करता है AtomicReferenceऔर न तो संदर्भ और न ही उसके लक्ष्य को उजागर करता है, बल्कि इसमें लक्ष्य को करने के तरीके शामिल हैं; एक बार जिस कोड को ऑब्जेक्ट वापस कर दिया गया था, AtomicReference[जिस पर उसके निर्माता ने एक प्रत्यक्ष संदर्भ रखा] को अमान्य और छोड़ दिया जाना चाहिए। यह उचित शब्दार्थ प्रदान करेगा, लेकिन यह धीमा और icky होगा।
सुपरकैट

70

जावा मूल्य से एक कॉल है

यह काम किस प्रकार करता है

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

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

  • यदि यह Foo foo = new Foo () जैसा कोई ऑब्जेक्ट डेटा प्रकार है, तो इस मामले में ऑब्जेक्ट के पते की प्रतिलिपि फ़ाइल शॉर्टकट की तरह है, मान लें कि हमारे पास C: \ डेस्कटॉप पर एक टेक्स्ट फ़ाइल abc.txt है और मान लें कि हम शॉर्टकट बनाते हैं एक ही फ़ाइल और इसे C: \ desktop \ abc- शॉर्टकट के अंदर डालें, ताकि जब आप C: \ desktop \ abc.txt से फ़ाइल का उपयोग करें और 'Stack Overflow' लिखें और फ़ाइल को बंद करें और फिर से फ़ाइल को शॉर्टकट से खोलें तो आप लिखना 'प्रोग्रामरों के लिए सीखने के लिए सबसे बड़ा ऑनलाइन समुदाय है' तो कुल फ़ाइल परिवर्तन होगा 'ढेर अतिप्रवाह प्रोग्रामर के लिए सबसे बड़ा ऑनलाइन समुदाय है'इसका मतलब यह है कि जहां आप फ़ाइल खोलते हैं, उससे कोई फर्क नहीं पड़ता, हर बार जब हम एक ही फ़ाइल तक पहुंच रहे थे, तो हम मान सकते हैंफ़ाइल के रूप में फू और मान लीजिए कि 123HD7h ( C: \ desktop \ abc.txt का मूल पता ) और 234jdid ( C: \ desktop \ abc- शॉर्टकट की तरह कॉपी किया गया पता, जिसमें वास्तव में फ़ाइल का मूल पता शामिल है ) पर संग्रहीत foo है । तो बेहतर समझ के लिए शॉर्टकट फ़ाइल और महसूस करें ..


66

पहले से ही महान उत्तर हैं जो इसे कवर करते हैं। मैं एक बहुत ही सरल उदाहरण (जो संकलित करूंगा) को c ++ में पास-बाय-रेफरेंस और जावा में पास-बाय-वैल्यू के बीच के व्यवहार के विपरीत साझा करके एक छोटा सा योगदान करना चाहता था ।

कुछ बिंदु:

  1. "संदर्भ" शब्द दो अलग-अलग अर्थों के साथ एक अतिभारित है। जावा में इसका सीधा मतलब एक पॉइंटर होता है, लेकिन "पास-बाय-रेफरेंस" के संदर्भ में इसका मतलब है कि मूल वेरिएबल का हैंडल जो इसमें पास किया गया था।
  2. जावा पास-दर-मूल्य है । जावा C (अन्य भाषाओं के बीच) का एक वंशज है। सी से पहले, कई (लेकिन सभी नहीं) पहले की तरह फोरट्रान और कोबोल जैसी भाषाओं ने पीबीआर का समर्थन किया था, लेकिन सी ने नहीं किया। पीबीआर ने इन अन्य भाषाओं को उप-रूटीन के अंदर पारित चर में बदलाव करने की अनुमति दी। एक ही चीज़ को पूरा करने के लिए (यानी फ़ंक्शन के अंदर चर के मूल्यों को बदलना), सी प्रोग्रामर ने फ़ंक्शन में चर के लिए संकेत दिए। सी से प्रेरित भाषाएं, जैसे कि जावा, ने इस विचार को उधार लिया और सी के रूप में तरीकों के लिए सूचक को पास करना जारी रखा, सिवाय इसके कि जावा अपने पॉइंटर्स संदर्भ कहता है। फिर, यह "पास-बाय-संदर्भ" की तुलना में "संदर्भ" शब्द का एक अलग उपयोग है।
  3. C ++ "और" वर्ण का उपयोग करके एक संदर्भ पैरामीटर घोषित करके पास-दर-संदर्भ की अनुमति देता है (जो कि C और C ++ दोनों में "एक चर का पता" इंगित करने के लिए उपयोग किया जाने वाला एक ही वर्ण है)। उदाहरण के लिए, यदि हम संदर्भ से एक पॉइंटर में पास होते हैं, तो पैरामीटर और तर्क केवल एक ही ऑब्जेक्ट की ओर इशारा नहीं करते हैं। बल्कि, वे एक ही चर हैं। यदि कोई अलग पते पर या अशक्त हो जाता है, तो दूसरा करता है।
  4. नीचे C ++ उदाहरण में मैं एक पॉइंटर को संदर्भ द्वारा एक शून्य समाप्त स्ट्रिंग के लिए पास कर रहा हूं । और नीचे जावा उदाहरण में मैं एक स्ट्रिंग के लिए एक जावा संदर्भ (फिर से, एक स्ट्रिंग के लिए एक संकेतक के रूप में) पास कर रहा हूं। टिप्पणियों में आउटपुट पर ध्यान दें।

संदर्भ उदाहरण द्वारा C ++ पास:

using namespace std;
#include <iostream>

void change (char *&str){   // the '&' makes this a reference parameter
    str = NULL;
}

int main()
{
    char *str = "not Null";
    change(str);
    cout<<"str is " << str;      // ==>str is <null>
}

जावा मान उदाहरण के लिए "एक जावा संदर्भ"

public class ValueDemo{

    public void change (String str){
        str = null;
    }

     public static void main(String []args){
        ValueDemo vd = new ValueDemo();
        String str = "not null";
        vd.change(str);
        System.out.println("str is " + str);    // ==> str is not null!!
                                                // Note that if "str" was
                                                // passed-by-reference, it
                                                // WOULD BE NULL after the
                                                // call to change().
     }
}

संपादित करें

कई लोगों ने टिप्पणियाँ लिखी हैं जो यह प्रतीत करती हैं कि या तो वे मेरे उदाहरण नहीं देख रहे हैं या उन्हें c ++ का उदाहरण नहीं मिला है। निश्चित नहीं है कि डिस्कनेक्ट कहां है, लेकिन सी ++ उदाहरण का अनुमान लगाना स्पष्ट नहीं है। मैं पास्कल में एक ही उदाहरण पोस्ट कर रहा हूं क्योंकि मुझे लगता है कि पास-दर-संदर्भ पास्कल में क्लीनर दिखता है, लेकिन मैं गलत हो सकता है। मैं सिर्फ लोगों को अधिक भ्रमित कर सकता हूं; मुझे आशा नहीं है।

पास्कल में, पारित-दर-संदर्भ को "var पैरामीटर" कहा जाता है। नीचे दिए गए कार्यविधि में, कृपया '' वेर '' जो 'पैरामीटर' 'से पहले वाले कीवर्ड पर ध्यान दें। जब इस प्रक्रिया के लिए एक पॉइंटर पास किया जाता है, तो इसे संदर्भ द्वारा पास किया जाएगा । व्यवहार पर ध्यान दें: जब यह प्रक्रिया ptr को nil पर सेट करती है (जो NULL के लिए पास्कल स्पीक है), तो यह nil को तर्क देगा - आप जावा में ऐसा नहीं कर सकते।

program passByRefDemo;
type 
   iptr = ^integer;
var
   ptr: iptr;

   procedure setToNil(var ptr : iptr);
   begin
       ptr := nil;
   end;

begin
   new(ptr);
   ptr^ := 10;
   setToNil(ptr);
   if (ptr = nil) then
       writeln('ptr seems to be nil');     { ptr should be nil, so this line will run. }
end.

EDIT 2

केन अर्नोल्ड, जेम्स गोसलिंग (जावा का आविष्कार करने वाला लड़का) , और डेविड होम्स, अध्याय 2, खंड 2.6.5 द्वारा "द जावा प्रोग्रामिंग लैंग्वेज" के कुछ अंश

विधियों के सभी मापदंडों को "मूल्य से" पारित किया जाता है । दूसरे शब्दों में, एक विधि में पैरामीटर चर के मान तर्क के रूप में निर्दिष्ट इनवोक की प्रतियां हैं।

वह वस्तुओं के संबंध में समान बिंदु बनाता है। । ।

आपको ध्यान देना चाहिए कि जब पैरामीटर ऑब्जेक्ट रेफरेंस होता है, तो वह ऑब्जेक्ट रेफरेंस होता है-ऑब्जेक्ट ही नहीं-जो "वैल्यू बाय" पास होता है

और उसी खंड के अंत में वह जावा के बारे में एक व्यापक बयान देता है जो केवल मूल्य से गुजरता है और संदर्भ से कभी नहीं गुजरता है।

जावा प्रोग्रामिंग भाषा वस्तुओं को संदर्भ से पारित नहीं करती है; यह मान द्वारा वस्तु संदर्भों को पास करता है । क्योंकि एक ही संदर्भ की दो प्रतियां एक ही वास्तविक वस्तु को संदर्भित करती हैं, एक संदर्भ चर के माध्यम से किए गए परिवर्तन दूसरे के माध्यम से दिखाई देते हैं। वास्तव में एक पैरामीटर पासिंग मोड है- वैल्यू - पास से गुजरता है जो चीजों को सरल रखने में मदद करता है।

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

मुझे लगता है कि दो मॉडलों के बीच का अंतर बहुत सूक्ष्म है और जब तक आप प्रोग्रामिंग नहीं करते हैं जहां आपने वास्तव में पास-बाय-संदर्भ का उपयोग किया है, तो यह याद रखना आसान है जहां दो मॉडल भिन्न हैं।

मुझे उम्मीद है कि यह बहस सुलझाएगा, लेकिन शायद नहीं होगा।

EDIT 3

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

यही कारण है कि केवल जावा डेवलपर्स के पास इसके साथ समस्या है। वे "संदर्भ" शब्द को देखते हैं और सोचते हैं कि वे वास्तव में इसका मतलब जानते हैं, इसलिए वे विरोधी तर्क पर विचार करने के लिए परेशान नहीं करते हैं।

वैसे भी, मैंने एक पुरानी पोस्ट में एक टिप्पणी देखी, जिसने एक गुब्बारा सादृश्य बनाया, जो मुझे वास्तव में पसंद आया। इतना कि मैंने बिंदु को चित्रित करने के लिए कार्टून का एक सेट बनाने के लिए कुछ क्लिप-आर्ट को एक साथ गोंद करने का फैसला किया।

मान द्वारा एक संदर्भ पास करना - संदर्भ में परिवर्तन कॉलर के दायरे में परिलक्षित नहीं होता है, लेकिन ऑब्जेक्ट में परिवर्तन होते हैं। ऐसा इसलिए है क्योंकि संदर्भ की प्रतिलिपि बनाई गई है, लेकिन मूल और प्रतिलिपि दोनों एक ही वस्तु को संदर्भित करते हैं। मान द्वारा पासिंग ऑब्जेक्ट संदर्भ

संदर्भ से गुजारें - संदर्भ की कोई प्रति नहीं है। सिंगल संदर्भ को कॉलर और फ़ंक्शन दोनों द्वारा साझा किया जाता है। संदर्भ या ऑब्जेक्ट के डेटा में कोई भी परिवर्तन कॉलर के दायरे में परिलक्षित होते हैं। संदर्भ से गुजारें

EDIT 4

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

जब विधि या कंस्ट्रक्टर को लागू किया जाता है ()15.12), वास्तविक तर्क अभिव्यक्तियों का मान विधि या कंस्ट्रक्टर के निकाय के निष्पादन से पहले, नए बनाए गए पैरामीटर चर, प्रत्येक के घोषित प्रकार को आरंभ करता है। DeclaratorId में प्रकट होने वाले पहचानकर्ता को औपचारिक पैरामीटर को संदर्भित करने के लिए विधि या निर्माणकर्ता के शरीर में एक साधारण नाम के रूप में उपयोग किया जा सकता है।

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

वापस जब मैंने 90 के दशक में कम्पाइलर का अध्ययन किया, मैंने 1986 से पुस्तक के पहले संस्करण का उपयोग किया, जो लगभग 9 या 10 वर्षों से जावा पूर्व-दिनांकित था। हालाँकि, मैं बस की एक प्रति भर में भाग गया २०० which से २ एडी जिसमें वास्तव में जावा का उल्लेख है! धारा 1.6.6 में "पैरामीटर पासिंग मैकेनिज्म" का लेबल दिया गया है, जो पैरामीटर को बहुत अच्छी तरह से गुजरता है। यहाँ शीर्षक "कॉल-बाय-वैल्यू" के तहत एक अंश है जिसमें जावा का उल्लेख है:

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


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

1
@JuanMendes, मैंने सिर्फ एक उदाहरण के रूप में C ++ का उपयोग किया; मैं आपको अन्य भाषाओं में उदाहरण दे सकता हूं। C ++ मौजूद होने से बहुत पहले "संदर्भ द्वारा पास" शब्द मौजूद था। यह एक बहुत विशिष्ट परिभाषा के साथ एक पाठ्यपुस्तक शब्द है। और परिभाषा के अनुसार, जावा संदर्भ से नहीं गुजरता है। यदि आप चाहें तो इस शब्द का उपयोग कर सकते हैं, लेकिन आपका उपयोग पाठ्यपुस्तक की परिभाषा के अनुरूप नहीं होगा। यह सिर्फ एक पॉइंटर को पॉइंटर नहीं है। यह "पास बाय संदर्भ" की अनुमति देने के लिए भाषा द्वारा प्रदान किया गया एक निर्माण है। कृपया मेरे उदाहरण पर करीब से नज़र डालें, लेकिन कृपया इसके लिए मेरा शब्द न लें और इसे अपने लिए देखें।
संजीव

2
@AutomatedMike मुझे लगता है कि जावा को "पास-बाय-रेफरेंस" के रूप में वर्णित करना भी भ्रामक है, उनका संदर्भ पॉइंटर्स से अधिक कुछ नहीं है। जैसा कि संजीव ने लिखा है, संदर्भ और पॉइंटर पाठ्यपुस्तक की शर्तें हैं जिनका जावा निर्माता क्या उपयोग करते हैं, इसका अपना अर्थ है।
जोद्रेज डुडविविज़

1
@ArtanisZeratul बिंदु सूक्ष्म है, लेकिन जटिल नहीं है। कृपया मेरे द्वारा पोस्ट किए गए कार्टून पर एक नज़र डालें। मैंने महसूस किया कि यह पालन करना बहुत सरल था। वह जावा पास-बाय-वैल्यू है, केवल एक राय नहीं है। यह पास-दर-मूल्य की पाठ्यपुस्तक परिभाषा से सच है। इसके अलावा, "जो लोग हमेशा कहते हैं कि यह मूल्य से गुजरता है" में जावा के निर्माता जेम्स गोसलिंग जैसे कंप्यूटर वैज्ञानिक शामिल हैं। कृपया मेरी पोस्ट में "संपादित 2" के तहत उनकी पुस्तक के उद्धरण देखें।
संजीव

1
क्या एक महान जवाब, "पास से संदर्भ" जावा (और जेएस जैसी अन्य भाषाओं) में मौजूद नहीं है।
newfolder

56

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

public static void swap(StringBuffer s1, StringBuffer s2) {
    StringBuffer temp = s1;
    s1 = s2;
    s2 = temp;
}


public static void main(String[] args) {
    StringBuffer s1 = new StringBuffer("Hello");
    StringBuffer s2 = new StringBuffer("World");
    swap(s1, s2);
    System.out.println(s1);
    System.out.println(s2);
}

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

public static void appendWorld(StringBuffer s1) {
    s1.append(" World");
}

public static void main(String[] args) {
    StringBuffer s = new StringBuffer("Hello");
    appendWorld(s);
    System.out.println(s);
}

यह हैलो वर्ल्ड को कमांड लाइन पर पॉप्युलेट करेगा। अगर आप StringBuffer को String में बदलते हैं तो यह सिर्फ Hello का उत्पादन करेगा क्योंकि String अपरिवर्तनीय है। उदाहरण के लिए:

public static void appendWorld(String s){
    s = s+" World";
}

public static void main(String[] args) {
    String s = new String("Hello");
    appendWorld(s);
    System.out.println(s);
}

हालाँकि आप स्ट्रिंग के लिए एक रैपर बना सकते हैं जो इसे स्ट्रिंग्स के साथ उपयोग करने में सक्षम बनाता है:

class StringWrapper {
    public String value;

    public StringWrapper(String value) {
        this.value = value;
    }
}

public static void appendWorld(StringWrapper s){
    s.value = s.value +" World";
}

public static void main(String[] args) {
    StringWrapper s = new StringWrapper("Hello");
    appendWorld(s);
    System.out.println(s.value);
}

संपादित करें: मेरा मानना ​​है कि यह स्ट्रिंगरबफ़र का उपयोग करने का कारण भी है जब यह दो स्ट्रिंग्स को "जोड़ने" की बात आती है क्योंकि आप मूल वस्तु को संशोधित कर सकते हैं जो कि स्ट्रिंग जैसी अपरिवर्तनीय वस्तुओं के साथ नहीं हो सकता है।


स्वैप टेस्ट के लिए +1 - संदर्भ से गुजरने और मूल्य द्वारा संदर्भ को पारित करने के बीच अंतर करने के लिए शायद सबसे सीधा और भरोसेमंद तरीका है । Iff आप आसानी से एक समारोह में लिख सकते हैं swap(a, b)(1) स्वैप कि aऔर bफोन करने वाले का पीओवी से, (2) प्रकार नास्तिक इस हद तक कि स्थिर टाइपिंग की अनुमति देता है के लिए है (एक अन्य प्रकार के साथ इसे का उपयोग अर्थ की घोषित प्रकार बदलते से ज्यादा कुछ नहीं की आवश्यकता है aऔर b) , और (3) कॉलर को स्पष्ट रूप से एक पॉइंटर या नाम पास करने की आवश्यकता नहीं होती है, फिर भाषा संदर्भ से गुजरने का समर्थन करती है।
cHao

".. आदिम डेटाटाइप्स के लिए आप एक कॉपी के साथ काम करेंगे और ऑब्जेक्ट्स के लिए आप वस्तुओं के संदर्भ की एक कॉपी के साथ काम करेंगे" - पूरी तरह से लिखा गया है!
राउल

55

नहीं, यह संदर्भ से नहीं है।

जावा जावा लैंग्वेज स्पेसिफिकेशन के अनुसार वैल्यू से पास होता है:

जब विधि या कंस्ट्रक्टर को लागू किया जाता है ()15.12), वास्तविक तर्क अभिव्यक्तियों का मान विधि या कंस्ट्रक्टर के निकाय के निष्पादन से पहले, नए बनाए गए पैरामीटर चर , प्रत्येक के घोषित प्रकार को आरंभ करता है । DeclaratorId में प्रकट होने वाले पहचानकर्ता को औपचारिक पैरामीटर को संदर्भित करने के लिए विधि या निर्माणकर्ता के शरीर में एक साधारण नाम के रूप में उपयोग किया जा सकता है ।


52

मुझे चार उदाहरणों की मदद से अपनी समझ समझाने की कोशिश करते हैं। जावा पास-बाय-वैल्यू है, न कि पास-बाय-रेफरेंस

/ **

मूल्य से गुजारें

जावा में, सभी पैरामीटर मान द्वारा पारित किए जाते हैं, अर्थात कॉल करने के लिए विधि तर्क असाइन करना दिखाई नहीं देता है।

* /

उदाहरण 1:

public class PassByValueString {
    public static void main(String[] args) {
        new PassByValueString().caller();
    }

    public void caller() {
        String value = "Nikhil";
        boolean valueflag = false;
        String output = method(value, valueflag);
        /*
         * 'output' is insignificant in this example. we are more interested in
         * 'value' and 'valueflag'
         */
        System.out.println("output : " + output);
        System.out.println("value : " + value);
        System.out.println("valueflag : " + valueflag);

    }

    public String method(String value, boolean valueflag) {
        value = "Anand";
        valueflag = true;
        return "output";
    }
}

परिणाम

output : output
value : Nikhil
valueflag : false

उदाहरण 2:

/ ** * * मूल्य से पास * * /

public class PassByValueNewString {
    public static void main(String[] args) {
        new PassByValueNewString().caller();
    }

    public void caller() {
        String value = new String("Nikhil");
        boolean valueflag = false;
        String output = method(value, valueflag);
        /*
         * 'output' is insignificant in this example. we are more interested in
         * 'value' and 'valueflag'
         */
        System.out.println("output : " + output);
        System.out.println("value : " + value);
        System.out.println("valueflag : " + valueflag);

    }

    public String method(String value, boolean valueflag) {
        value = "Anand";
        valueflag = true;
        return "output";
    }
}

परिणाम

output : output
value : Nikhil
valueflag : false

उदाहरण 3:

/ ** इस 'पास बाय वैल्यू' में 'पास बाय संदर्भ' की भावना है।

कुछ लोग कहते हैं कि आदिम प्रकार और 'स्ट्रिंग' 'मूल्य से पास' हैं और ऑब्जेक्ट 'संदर्भ द्वारा पास' हैं।

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

* /

public class PassByValueObjectCase1 {

    private class Student {
        int id;
        String name;
        public Student() {
        }
        public Student(int id, String name) {
            super();
            this.id = id;
            this.name = name;
        }
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return "Student [id=" + id + ", name=" + name + "]";
        }
    }

    public static void main(String[] args) {
        new PassByValueObjectCase1().caller();
    }

    public void caller() {
        Student student = new Student(10, "Nikhil");
        String output = method(student);
        /*
         * 'output' is insignificant in this example. we are more interested in
         * 'student'
         */
        System.out.println("output : " + output);
        System.out.println("student : " + student);
    }

    public String method(Student student) {
        student.setName("Anand");
        return "output";
    }
}

परिणाम

output : output
student : Student [id=10, name=Anand]

उदाहरण 4:

/ **

उदाहरण 3 (PassByValueObjectCase1.java) में जो उल्लेख किया गया था, उसके अलावा, हम वास्तविक संदर्भ को मूल दायरे से बाहर नहीं बदल सकते। "

नोट: मैं के लिए कोड पेस्ट नहीं कर रहा हूँ private class Student। कक्षा की परिभाषा Studentउदाहरण 3 के समान है।

* /

public class PassByValueObjectCase2 {

    public static void main(String[] args) {
        new PassByValueObjectCase2().caller();
    }

    public void caller() {
        // student has the actual reference to a Student object created
        // can we change this actual reference outside the local scope? Let's see
        Student student = new Student(10, "Nikhil");
        String output = method(student);
        /*
         * 'output' is insignificant in this example. we are more interested in
         * 'student'
         */
        System.out.println("output : " + output);
        System.out.println("student : " + student); // Will it print Nikhil or Anand?
    }

    public String method(Student student) {
        student = new Student(20, "Anand");
        return "output";
    }

}

परिणाम

output : output
student : Student [id=10, name=Nikhil]

49

आप जावा में संदर्भ से कभी नहीं गुजर सकते हैं, और एक तरीका है जो स्पष्ट है जब आप एक विधि कॉल से एक से अधिक मान लौटना चाहते हैं। C ++ में निम्नलिखित बिट कोड पर विचार करें:

void getValues(int& arg1, int& arg2) {
    arg1 = 1;
    arg2 = 2;
}
void caller() {
    int x;
    int y;
    getValues(x, y);
    cout << "Result: " << x << " " << y << endl;
}

कभी-कभी आप जावा में एक ही पैटर्न का उपयोग करना चाहते हैं, लेकिन आप नहीं कर सकते हैं; कम से कम सीधे तौर पर तो नहीं। इसके बजाय आप ऐसा कुछ कर सकते हैं:

void getValues(int[] arg1, int[] arg2) {
    arg1[0] = 1;
    arg2[0] = 2;
}
void caller() {
    int[] x = new int[1];
    int[] y = new int[1];
    getValues(x, y);
    System.out.println("Result: " + x[0] + " " + y[0]);
}

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


48

मैंने सोचा कि मैं विनिर्देशों से अधिक विवरण जोड़ने के लिए इस उत्तर में योगदान दूंगा।

प्रथम, संदर्भ बनाम पासिंग के बीच अंतर क्या है?

संदर्भ से गुजरने का मतलब है कि फंक्शंस का पैरामीटर वैसा ही होगा जैसे कॉलर्स की पास की गई दलील (मान नहीं, बल्कि पहचान - चर ही)।

मूल्य द्वारा पास का मतलब है कि फंक्शंस का पैरामीटर कॉलर्स के पास किए गए तर्क की एक प्रति होगी।

या विकिपीडिया से, पास-पास-संदर्भ के विषय पर

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

और पास-पास-मूल्य के विषय पर

कॉल-बाय-वैल्यू में, तर्क अभिव्यक्ति का मूल्यांकन किया जाता है, और परिणामी मान फ़ंक्शन में संबंधित चर के लिए बाध्य होता है [...]। यदि फ़ंक्शन या प्रक्रिया अपने मापदंडों को मान प्रदान करने में सक्षम है, तो केवल इसकी स्थानीय प्रति असाइन की गई है [...]।

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

जब विधि या कंस्ट्रक्टर को लागू किया जाता है ()15.12), वास्तविक तर्क अभिव्यक्तियों का मान विधि या कंस्ट्रक्टर के निकाय के निष्पादन से पहले, नए बनाए गए पैरामीटर चर , प्रत्येक के घोषित प्रकारों को आरंभ करता है

तो यह इसी पैरामीटर चर के लिए तर्क का मूल्य प्रदान करता है (या बांधता है)।

तर्क का मूल्य क्या है?

आइए संदर्भ प्रकारों पर विचार करें, जावा वर्चुअल मशीन विशिष्टता राज्य

तीन प्रकार के संदर्भ प्रकार होते हैं : वर्ग प्रकार, सरणी प्रकार और इंटरफ़ेस प्रकार। उनके मूल्य क्रमशः गतिशील रूप से निर्मित वर्ग उदाहरणों, सरणियों, या वर्ग उदाहरणों या सरणियों के संदर्भ हैं जो इंटरफेस को लागू करते हैं।

जावा भाषा विशिष्टता भी कहा गया है

संदर्भ मान (अक्सर केवल संदर्भ) इन वस्तुओं के संकेत होते हैं , और एक विशेष अशक्त संदर्भ, जो किसी वस्तु को संदर्भित नहीं करता है।

एक तर्क का मूल्य (कुछ संदर्भ प्रकार का) किसी वस्तु का सूचक है। ध्यान दें कि एक चर, एक संदर्भ प्रकार वापसी के साथ एक विधि का एक आह्वान और एक उदाहरण सृजन अभिव्यक्ति (new ... ) सभी एक संदर्भ प्रकार के मूल्य के लिए हल करते हैं।

इसलिए

public void method (String param) {}
...
String var = new String("ref");
method(var);
method(var.toString());
method(new String("ref"));

सभी एक संदर्भ के मूल्य Stringको विधि के नए बनाए गए पैरामीटर, उदाहरण के लिए बांधते हैं param। यह वही है जो पास-दर-मूल्य की परिभाषा का वर्णन करता है। जैसे, जावा पास-बाय-वैल्यू है

तथ्य यह है कि आप किसी विधि को लागू करने के लिए संदर्भ का अनुसरण कर सकते हैं या संदर्भित ऑब्जेक्ट के किसी क्षेत्र तक पहुंचने के लिए बातचीत के लिए पूरी तरह से अप्रासंगिक है। पास-दर-संदर्भ की परिभाषा थी

इसका आम तौर पर अर्थ है कि फ़ंक्शन को संशोधित किया जा सकता है (यानी असाइन करें) चर को तर्क के रूप में उपयोग किया जाता है - ऐसा कुछ जो इसके कॉलर द्वारा देखा जाएगा।

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


जावा वर्चुअल मशीन स्पेसिफिकेशन में आदिम मूल्यों को भी परिभाषित किया गया है । प्रकार का मूल्य संगत अभिन्न या अस्थायी बिंदु मान है, जो उचित रूप से एन्कोडेड है (8, 16, 32, 64, आदि बिट्स)।


42

जावा में केवल संदर्भों को पारित किया जाता है और मूल्य द्वारा पारित किया जाता है:

जावा तर्क सभी मूल्य द्वारा पारित किए जाते हैं (विधि द्वारा उपयोग किए जाने पर संदर्भ की प्रतिलिपि बनाई जाती है):

आदिम प्रकारों के मामले में, जावा व्यवहार सरल है: मूल्य को आदिम प्रकार के एक और उदाहरण में कॉपी किया जाता है।

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

व्यवहार आदिम प्रकारों से अलग दिखाई दे सकता है: क्योंकि कॉपी किए गए ऑब्जेक्ट-चर में एक ही पता (एक ही ऑब्जेक्ट) होता है। ऑब्जेक्ट की सामग्री / सदस्यों को अभी भी एक विधि के भीतर संशोधित किया जा सकता है और बाद में बाहर तक पहुंच सकता है, यह भ्रम प्रदान करता है कि (युक्त) ऑब्जेक्ट स्वयं संदर्भ द्वारा पारित किया गया था।

"स्ट्रिंग" ऑब्जेक्ट शहरी किंवदंती के लिए एक अच्छा काउंटर-उदाहरण प्रतीत होता है, जिसमें कहा गया है कि "ऑब्जेक्ट्स संदर्भ से पारित हो जाते हैं":

वास्तव में, एक विधि का उपयोग करके, आप कभी भी स्ट्रिंग के मान को तर्क के रूप में अपडेट नहीं कर पाएंगे:

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


तो यह आदिम के संबंध में वस्तुओं और byVal के संबंध में byRef है?
मोक्स

@ मॉक्स कृपया पढ़ें: वस्तुओं को संदर्भ से पारित नहीं किया जाता है, यह एक नेतृत्व है: स्ट्रिंग a = नया स्ट्रिंग ("अपरिवर्तित");
user1767316

1
@Aaron "Pass by reference" का मतलब यह नहीं है कि "एक मान पास करें जो एक प्रकार का सदस्य है जिसे जावा में 'संदर्भ' कहा जाता है। "संदर्भ" के दो उपयोगों का मतलब अलग-अलग चीजें हैं।
फिलीपींस ६xy ’

2
काफी उलझन भरा जवाब। एक स्ट्रिंग ऑब्जेक्ट को एक विधि में क्यों नहीं बदल सकते इसका कारण, जिसे संदर्भ द्वारा पारित किया गया है, यह है कि स्ट्रिंग ऑब्जेक्ट डिज़ाइन द्वारा अपरिवर्तनीय हैं और आप ऐसा नहीं कर सकतेstrParam.setChar ( i, newValue ) । उस ने कहा, स्ट्रिंग्स, किसी भी चीज के रूप में, मूल्य द्वारा पारित किए जाते हैं और, चूंकि स्ट्रिंग एक गैर-आदिम प्रकार है, यह मान उस चीज़ का संदर्भ है जिसे नए के साथ बनाया गया था, और आप इसे String.intern () का उपयोग करके जांच सकते हैं ।
जक्कम

1
इसके बजाय, आप param = "एक और स्ट्रिंग" (नए स्ट्रिंग ("एक और स्ट्रिंग" के बराबर)) के माध्यम से एक स्ट्रिंग नहीं बदल सकते क्योंकि परम का संदर्भ मूल्य (जो अब "एक और स्ट्रिंग" की ओर इशारा करता है) विधि से वापस नहीं आ सकता है तन। लेकिन यह किसी भी अन्य वस्तु के लिए सच है, अंतर यह है कि, जब वर्ग इंटरफ़ेस इसके लिए अनुमति देता है, तो आप कर सकते हैं param.changeMe () और संदर्भित की जा रही शीर्ष स्तर की वस्तु बदल जाएगी क्योंकि परम इसके संदर्भ मूल्य के बावजूद खुद को इंगित कर रहा है (सी स्थिति में, पता स्थान) विधि से वापस पॉप नहीं हो सकता।
जक्कम

39

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


2
मुझे आपका दूसरा-से-अंतिम वाक्य बहुत भ्रामक लगता है। यह सच नहीं है कि "जावा में सभी ऑब्जेक्ट संदर्भ हैं"। यह केवल उन वस्तुओं का संदर्भ है जो संदर्भ हैं।
दाऊद इब्न करीम

37

जैसा कि कई लोगों ने पहले उल्लेख किया है, जावा हमेशा पास-पास-मूल्य है

यहाँ एक और उदाहरण है जो आपको अंतर समझने में मदद करेगा ( क्लासिक स्वैप उदाहरण ):

public class Test {
  public static void main(String[] args) {
    Integer a = new Integer(2);
    Integer b = new Integer(3);
    System.out.println("Before: a = " + a + ", b = " + b);
    swap(a,b);
    System.out.println("After: a = " + a + ", b = " + b);
  }

  public static swap(Integer iA, Integer iB) {
    Integer tmp = iA;
    iA = iB;
    iB = tmp;
  }
}

प्रिंटों:

पहले: एक = 2, बी = 3
बाद: a = 2, b = 3

ऐसा इसलिए होता है क्योंकि iA और iB नए स्थानीय संदर्भ चर हैं जिनके पास दिए गए संदर्भों का समान मूल्य है (वे क्रमशः a और b की ओर संकेत करते हैं)। इसलिए, iA या iB के संदर्भों को बदलने की कोशिश केवल स्थानीय दायरे में बदलेगी और इस पद्धति के बाहर नहीं।


32

जावा में केवल मूल्य है। इसे मान्य करने के लिए एक बहुत ही सरल उदाहरण है।

public void test() {
    MyClass obj = null;
    init(obj);
    //After calling init method, obj still points to null
    //this is because obj is passed as value and not as reference.
}
private void init(MyClass objVar) {
    objVar = new MyClass();
}

4
यह देखने का सबसे स्पष्ट, सरल तरीका है कि जावा मूल्य से गुजरता है। का मान obj( null) पास किया गया था init, संदर्भ के लिए नहीं obj
डेविड श्वार्ट्ज

31

मैं हमेशा इसे "कॉपी द्वारा पास" के रूप में सोचता हूं। यह मूल्य की एक प्रति है यह आदिम या संदर्भ है। यदि यह एक आदिम है तो यह बिट्स की एक प्रति है जो मूल्य हैं और यदि यह एक वस्तु है तो यह संदर्भ की एक प्रति है।

public class PassByCopy{
    public static void changeName(Dog d){
        d.name = "Fido";
    }
    public static void main(String[] args){
        Dog d = new Dog("Maxx");
        System.out.println("name= "+ d.name);
        changeName(d);
        System.out.println("name= "+ d.name);
    }
}
class Dog{
    public String name;
    public Dog(String s){
        this.name = s;
    }
}

जावा PassByCopy का उत्पादन:

name = Maxx
name = फ़िदो

आदिम आवरण वर्ग और स्ट्रिंग्स अपरिवर्तनीय हैं, इसलिए उन प्रकारों का उपयोग करने वाला कोई भी उदाहरण अन्य प्रकारों / वस्तुओं के समान काम नहीं करेगा।


5
"पास से कॉपी" पास-दर-मूल्य का मतलब क्या है
टीजे क्राउडर

@TJCrowder। "पास से कॉपी" जावा प्रयोजनों के लिए एक ही अवधारणा को व्यक्त करने का एक और अधिक उपयुक्त तरीका हो सकता है: क्योंकि शब्दार्थ यह संदर्भ के माध्यम से गुजरने के लिए एक विचार के समान करने में बहुत मुश्किल बनाता है, जो कि आप जावा में चाहते हैं।
माइक कृंतक

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

28

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

जब कोई विधि किसी आदिम-प्रकार के पैरामीटर को संशोधित करती है, तो कॉलिंग विधि में मूल तर्क मान पर पैरामीटर में परिवर्तन का कोई प्रभाव नहीं पड़ता है।

जब वस्तुओं की बात आती है, तो वस्तुओं को स्वयं तरीकों से पारित नहीं किया जा सकता है। इसलिए हम ऑब्जेक्ट का संदर्भ (पता) पास करते हैं। हम इस संदर्भ का उपयोग करके मूल वस्तु में हेरफेर कर सकते हैं।

जावा कैसे ऑब्जेक्ट बनाता है और संग्रहीत करता है: जब हम एक ऑब्जेक्ट बनाते हैं तो हम ऑब्जेक्ट के पते को संदर्भ चर में संग्रहीत करते हैं। आइए निम्नलिखित कथन का विश्लेषण करें।

Account account1 = new Account();

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

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

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

नीचे दी गई छवि में आप देख सकते हैं कि हमारे पास दो संदर्भ चर हैं (इन्हें C / C ++ में पॉइंटर्स कहा जाता है, और मुझे लगता है कि यह शब्द इस सुविधा को समझना आसान बनाता है।) मुख्य विधि में। आदिम और संदर्भ चर स्टैक मेमोरी (नीचे की छवियों में बाईं ओर) में रखे जाते हैं। array1 और array2 संदर्भ चर "बिंदु" (जैसा कि C / C ++ प्रोग्रामर इसे कहते हैं) या क्रमशः a और b सरणियों के संदर्भ में, जो ऑब्जेक्ट हैं (मान इन संदर्भ चर पकड़ वस्तुओं के पते हैं) ढेर मेमोरी में (नीचे चित्र में दाईं ओर) ।

मान उदाहरण से गुजारें १

यदि हम array1 संदर्भ चर का मान रिवर्स एरे विधि के तर्क के रूप में पास करते हैं, तो विधि में एक संदर्भ चर बनाया जाता है और यह संदर्भ चर उसी सरणी (ए) की ओर इशारा करना शुरू कर देता है।

public class Test
{
    public static void reverseArray(int[] array1)
    {
        // ...
    }

    public static void main(String[] args)
    {
        int[] array1 = { 1, 10, -7 };
        int[] array2 = { 5, -190, 0 };

        reverseArray(array1);
    }
}

मान उदाहरण २ से गुजरें

तो, अगर हम कहते हैं

array1[0] = 5;

रिवर्स एरे विधि में, यह ए में बदलाव करेगा।

रिवर्स एरे विधि (array2) में एक और संदर्भ चर है जो एक सरणी c की ओर इशारा करता है। अगर हम कहते थे

array1 = array2;

RevArray मेथड में, फिर रेफरेंस array array1 मे मेथड रिवर्स ऐरे एरे की ओर इशारा करना बंद कर देगा और array c (दूसरी इमेज में डॉटेड लाइन) की ओर इशारा करने लगेगा।

अगर हम रेफरेंस वेरिएबल array2 का वैल्यू रिटर्न विधि के रिटर्न वैल्यू के रूप में उल्टा कर देते हैं और इस वैल्यू को रेफरेंस array1 से मेन मेथड में असाइन करते हैं, तो main में array1, array c की ओर इशारा करना शुरू कर देगा।

तो चलिए अब एक बार में हमारे द्वारा की गई सभी चीजें लिखें।

public class Test
{
    public static int[] reverseArray(int[] array1)
    {
        int[] array2 = { -7, 0, -1 };

        array1[0] = 5; // array a becomes 5, 10, -7

        array1 = array2; /* array1 of reverseArray starts
          pointing to c instead of a (not shown in image below) */
        return array2;
    }

    public static void main(String[] args)
    {
        int[] array1 = { 1, 10, -7 };
        int[] array2 = { 5, -190, 0 };

        array1 = reverseArray(array1); /* array1 of 
         main starts pointing to c instead of a */
    }
}

यहां छवि विवरण दर्ज करें

और अब जब रिवर्स एरे विधि समाप्त हो गई है, तो इसके संदर्भ चर (array1 और array2) चले गए हैं। जिसका अर्थ है कि अब हमारे पास मुख्य विधि array1 और array2 में केवल दो संदर्भ चर हैं जो क्रमशः c और b सरणियों को इंगित करते हैं। कोई संदर्भ चर ऑब्जेक्ट (सरणी) को इंगित कर रहा है a। तो यह कचरा संग्रहण के लिए योग्य है।

आप भी array2 के मुख्य में array2 का मान दे सकते हैं। array1 b को इंगित करना शुरू कर देगा।


27

मैंने यहाँ किसी भी प्रोग्रामिंग लैंग्वेज के लिए इस तरह के प्रश्नों के लिए एक थ्रेड तैयार किया है

जावा का भी उल्लेख है । यहाँ संक्षिप्त सारांश है:

  • Java इसे वैल्यू द्वारा पैरामीटर्स पास करता है
  • "by value" एक विधि में एक पैरामीटर पास करने के लिए जावा में एकमात्र तरीका है
  • पैरामीटर के रूप में दी गई ऑब्जेक्ट से विधियों का उपयोग करना ऑब्जेक्ट को मूल ऑब्जेक्ट्स के संदर्भ बिंदु के रूप में बदल देगा। (यदि यह विधि स्वयं कुछ मूल्यों को बदल देती है)

27

एक लंबी कहानी को छोटा करने के लिए, जावा ऑब्जेक्ट में कुछ बहुत ही अजीब गुण हैं।

सामान्य तौर पर, जावा आदिम प्रकार (है int, bool, char, double, आदि) मूल्य से सीधे पारित कर रहे हैं कि। फिर जावा में ऑब्जेक्ट्स (सब कुछ है जो इससे प्राप्त होता है)java.lang.Object ) है। ऑब्जेक्ट वास्तव में हमेशा एक संदर्भ के माध्यम से संभाला जाता है (एक संदर्भ एक सूचक है जिसे आप स्पर्श नहीं कर सकते हैं)। इसका मतलब है कि वास्तव में, वस्तुओं को संदर्भ द्वारा पारित किया जाता है, क्योंकि संदर्भ आमतौर पर दिलचस्प नहीं होते हैं। हालांकि इसका मतलब यह है कि आप यह नहीं बदल सकते हैं कि किस वस्तु को संदर्भ के रूप में इंगित किया गया है जो मूल्य द्वारा पारित किया गया है।

क्या यह आवाज़ अजीब और भ्रमित करने वाली है? आइए विचार करें कि संदर्भ के माध्यम से सी लागू कैसे होते हैं और मूल्य से गुजरते हैं। सी में, डिफ़ॉल्ट सम्मेलन मूल्य से पारित होता है। void foo(int x)मान से एक इंट पास करता है। void foo(int *x)एक ऐसा फ़ंक्शन है जो एक नहीं चाहता है int a, लेकिन एक इंट का सूचक है foo(&a):। एक &ऑपरेटर के साथ एक चर पते को पारित करने के लिए इसका उपयोग करेगा ।

इसे C ++ पर ले जाएं, और हमारे पास संदर्भ हैं। संदर्भ मूल रूप से (इस संदर्भ में) सिंटैक्टिक शुगर हैं जो समीकरण के पॉइंटर भाग को छिपाते हैं: void foo(int &x)द्वारा बुलाया जाता है foo(a), जहां कंपाइलर खुद जानता है कि यह एक संदर्भ है और गैर-संदर्भ का पता aपारित किया जाना चाहिए। जावा में, वस्तुओं का जिक्र करने वाले सभी चर वास्तव में संदर्भ प्रकार के होते हैं, प्रभाव के लिए जबरदस्ती कॉल के लिए मजबूर करने के लिए और ठीक दानेदार नियंत्रण (और जटिलता) के बिना उद्देश्यों के लिए उदाहरण के लिए, C ++।


मुझे लगता है कि यह जावा ऑब्जेक्ट और इसके संदर्भ के बारे में मेरी समझ के बहुत करीब है। जावा में ऑब्जेक्ट को संदर्भ प्रतिलिपि (या उपनाम) द्वारा एक विधि से पारित किया जाता है।
मैक्सजूम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.