2010-07-20 21 views
6

मुझे यह प्रश्न पूछने के लिए नौसिखिया की तरह लगता है - लेकिन यह क्यों है कि जब मैं नीचे अपनी विधि में सेट को पास करता हूं और इसे एक नए हैशसेट पर इंगित करता हूं, तो यह अभी भी एम्प्सेटसेट के रूप में आता है ? क्या ऐसा इसलिए है क्योंकि स्थानीय चर को ढेर पर आवंटित किया जाता है, और इसलिए जब मैं विधि से बाहर निकलता हूं तो नया उड़ा दिया जाता है? कैसे मैं कार्यात्मक समकक्ष प्राप्त कर सकता हूं?स्टैक बनाम ढेर पर जावा मेमोरी आवंटन

import java.util.HashSet; 
import java.util.Set; 

public class TestMethods { 

    public static void main(final String[] args) { 

     final Set<Integer> foo = java.util.Collections.emptySet(); 
     test(foo); 

    } 

    public static void test(Set<Integer> mySet) { 

     mySet = new HashSet<Integer>(); 

    } 

} 

उत्तर

8

जावा मूल्य द्वारा संदर्भ से गुजरता है, mySet के रूप में सिर्फ foo संदर्भ की एक प्रति के बारे में सोच। void test(Set<Integer> mySet) में, mySet चर उस फ़ंक्शन के भीतर केवल एक स्थानीय चर है, इसलिए इसे किसी अन्य चीज़ पर सेट करना main में कॉलर को प्रभावित नहीं करता है।

mySet संदर्भ (या "यदि आप चाहें तो" पॉइंट टू ") के समान सेट foo वैरिएबल main में होता है।

आप मुख्य में संदर्भ को बदलने के लिए चाहते हैं, तुम कर सकते हो जैसे: क्योंकि स्थानीय चर ढेर पर आवंटित किए जाते हैं

foo = test(); //foo can't be final now though 
public static Set<Integer> test() { 
    return new HashSet<Integer>(); 
} 
8

... यह है, और इसलिए अपने नए दूर जब उड़ा रहा है मैं विधि से बाहर निकलो?

नहीं। यह जावा के अर्थशास्त्र उत्तीर्ण तर्क के कारण है।

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

जब आप test विधि दर्ज करते हैं, तो आपके पास HashSet उदाहरण के संदर्भ में main विधि में निर्मित दो प्रतियां हैं; foo में से एक और mySet में से एक। आपका कोड तब नव निर्मित HashSet के संदर्भ के साथ mySet में संदर्भ को प्रतिस्थापित करता है, लेकिन यह नया संदर्भ कॉलर को वापस नहीं भेजा जाता है। (आप वापस test विधि के परिणाम के रूप में इसे पारित करने के ... उदाहरण के लिए अपने कोड को बदल सकता है लेकिन आप इस स्पष्ट रूप से क्या करना है।।)

ठीक है - लेकिन - अगर मैं ऐसा करने के लिए थे मेरे विधि कॉल के भीतर जोड़ें या कुछ अन्य ऑपरेशन, आवंटन संरक्षित किया जाएगा। ऐसा क्यों है?

है ऐसा इसलिए है क्योंकि जब आप foo या mySet में संदर्भ का उपयोग कर एक उदाहरण विधि कॉल, उस विधि वस्तु (HashSet) कि संदर्भ को संदर्भित करता है पर निष्पादित किया जाता है। यह मानते हुए कि दो संदर्भ एक ही वस्तु को इंगित करते हैं, आपका "आवंटन संरक्षित किया जाएगा"। या अधिक सटीक, आप किसी ऑब्जेक्ट के अन्य संदर्भों पर संचालन के माध्यम से किसी ऑब्जेक्ट के संदर्भ में संचालन के प्रभावों का निरीक्षण कर सकते हैं।

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

जिस तरह से आप Collections.emptySet() द्वारा दिए गए सेट में तत्व जोड़ने में सक्षम नहीं होंगे। वह सेट ऑब्जेक्ट अपरिवर्तनीय है।कॉलिंग (उदाहरण के लिए) add पर एक अपवाद फेंक देगा।

+0

ठीक है, लेकिन - कुछ अन्य आपरेशन के भीतर अगर मैं जोड़ सकता हूँ के लिए गए थे या मेरी विधि कॉल, कि आवंटन संरक्षित किया जाएगा। ऐसा क्यों है? –

+0

शानदार जवाब स्टीफन, धन्यवाद। –

0

यकीन नहीं है कि मैं सवाल समझता हूं। test विधि में, आप एक नया सेट तत्काल कर रहे हैं और इसे स्थानीय mySet चर पर असाइन कर रहे हैं। mySet तब foo के समान सेट को संदर्भित नहीं करेगा Main में वापस आता है।

जब आप विधि से वापस आते हैं, तो foo अभी भी मूल emptySet() का संदर्भ देता है और विधि में बनाए गए HashSet कचरा संग्रह के लिए चिह्नित किया जाएगा।

0
import java.util.HashSet; 
import java.util.Set; 

public class TestMethods { 

    public static void main(final String[] args) { 

     final Set<Integer> foo = java.util.Collections.emptySet(); 
     test(foo); 

    } 

    public static void test(Set<Integer> mySet) { 
     // here mySet points to the same object as foo in main 
     mySet = new HashSet<Integer>(); 
     // mySet now points to a new object created by your HashSet constructor call, 
     // any subsequent operations on mySet are no longer associated with foo, because 
     // they are no longer referencing the same object 
    } 
} 

मैं कार्यात्मक बराबर कैसे प्राप्त कर सकता है?

मुझे यकीन नहीं है कि मैं इस प्रश्न को समझता हूं, क्या आप वापसी की तलाश में हैं?

public static Set<Integer> test(Set<Integer> mySet) { 
     for(Integer i : mySet){ 
      // do something?? 
     } 
     mySet = new HashSet<Integer>(); 
     return mySet; 
    } 

अब, अगर आप foo आवंटित क्या परीक्षण रिटर्न, आप "कार्यात्मक समकक्ष" के लिए?

1

आपका 'foo' एक खाली सेट परीक्षण() कॉल में जा रहा करने के लिए भेजा, परीक्षण कॉल कि वस्तु को संशोधित नहीं किया था, और इसलिए यह अभी भी वहाँ से लौटने पर एक खाली सेट है।

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

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

0

आप इस पुस्तक को पढ़ना चाहिए:

"जावा SCJP प्रमाणन के लिए एक प्रोग्रामर की गाइड: एक व्यापक प्राइमर (3 संस्करण)"

+0

सूचक के लिए धन्यवाद। –

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