पहले से ही महान उत्तर हैं जो इसे कवर करते हैं। मैं एक बहुत ही सरल उदाहरण (जो संकलित करूंगा) को c ++ में पास-बाय-रेफरेंस और जावा में पास-बाय-वैल्यू के बीच के व्यवहार के विपरीत साझा करके एक छोटा सा योगदान करना चाहता था ।
कुछ बिंदु:
- "संदर्भ" शब्द दो अलग-अलग अर्थों के साथ एक अतिभारित है। जावा में इसका सीधा मतलब एक पॉइंटर होता है, लेकिन "पास-बाय-रेफरेंस" के संदर्भ में इसका मतलब है कि मूल वेरिएबल का हैंडल जो इसमें पास किया गया था।
- जावा पास-दर-मूल्य है । जावा C (अन्य भाषाओं के बीच) का एक वंशज है। सी से पहले, कई (लेकिन सभी नहीं) पहले की तरह फोरट्रान और कोबोल जैसी भाषाओं ने पीबीआर का समर्थन किया था, लेकिन सी ने नहीं किया। पीबीआर ने इन अन्य भाषाओं को उप-रूटीन के अंदर पारित चर में बदलाव करने की अनुमति दी। एक ही चीज़ को पूरा करने के लिए (यानी फ़ंक्शन के अंदर चर के मूल्यों को बदलना), सी प्रोग्रामर ने फ़ंक्शन में चर के लिए संकेत दिए। सी से प्रेरित भाषाएं, जैसे कि जावा, ने इस विचार को उधार लिया और सी के रूप में तरीकों के लिए सूचक को पास करना जारी रखा, सिवाय इसके कि जावा अपने पॉइंटर्स संदर्भ कहता है। फिर, यह "पास-बाय-संदर्भ" की तुलना में "संदर्भ" शब्द का एक अलग उपयोग है।
- C ++ "और" वर्ण का उपयोग करके एक संदर्भ पैरामीटर घोषित करके पास-दर-संदर्भ की अनुमति देता है (जो कि C और C ++ दोनों में "एक चर का पता" इंगित करने के लिए उपयोग किया जाने वाला एक ही वर्ण है)। उदाहरण के लिए, यदि हम संदर्भ से एक पॉइंटर में पास होते हैं, तो पैरामीटर और तर्क केवल एक ही ऑब्जेक्ट की ओर इशारा नहीं करते हैं। बल्कि, वे एक ही चर हैं। यदि कोई अलग पते पर या अशक्त हो जाता है, तो दूसरा करता है।
- नीचे 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 में "पैरामीटर पासिंग मैकेनिज्म" का लेबल दिया गया है, जो पैरामीटर को बहुत अच्छी तरह से गुजरता है। यहाँ शीर्षक "कॉल-बाय-वैल्यू" के तहत एक अंश है जिसमें जावा का उल्लेख है:
कॉल-बाय-वैल्यू में, वास्तविक पैरामीटर का मूल्यांकन किया जाता है (यदि यह एक अभिव्यक्ति है) या कॉपी किया गया (यदि यह एक चर है)। मूल्य को प्रक्रिया के संबंधित औपचारिक पैरामीटर से संबंधित स्थान में रखा गया है। इस पद्धति का उपयोग सी और जावा में किया जाता है, और सी ++ में एक आम विकल्प है, साथ ही अधिकांश अन्य भाषाओं में भी।