2012-02-16 21 views
14

मुझे आश्चर्य है कि निम्न लूप वस्तु का एक प्रति बनाता है, बल्कि मुझे इसका संदर्भ देने के बजाय। कारण यह है कि, पहला उदाहरण मेरी सरणी वस्तुओं को आवंटित नहीं करता है, लेकिन दूसरा करता है।जावा: प्रत्येक-लूप और संदर्भ

अपने सरणी
MyObject objects[] = new MyObject[6]; 
for (MyObject o: objects) { 

    o = new MyObject(); 
} 

MyObject objects[] = new MyObject[6]; 
for(int i = 0; i < objects.length; i++) { 

    objects[i] = new MyObject(); 
} 
+0

क्या वास्तव में जावा में मौजूद पहली तरह लूप वाक्यविन्यास के लिए एक है? –

+0

@ चंद्रशेखर: [प्रत्येक-लूप जावा] के लिए (http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html)। – RanRag

+0

@ चंद्रशेखर रणरग सही है। हालांकि, यह सवाल के लिए प्रासंगिक नहीं है।शायद ओपी सिर्फ अपने कोड को दोबारा लिखो, प्रतिलिपि/पेस्ट न करें और इसलिए अपनी पसंदीदा भाषा में सोचा। –

उत्तर

15

जावा कई अन्य भाषाओं की तुलना में थोड़ा अलग काम करता है। क्या o पहले उदाहरण में है बस वस्तु का संदर्भ है।

जब आप कहते हैं कि o = new MyObject(), यह प्रकार MyObject और उस वस्तु के लिए संदर्भ o की एक नई वस्तु बनाता है o से पहले संदर्भित जबकि objects[index]

यही है, ऑब्जेक्ट्स [इंडेक्स] ही स्मृति में किसी अन्य वस्तु का संदर्भ है। इसलिए ऑब्जेक्ट्स [इंडेक्स] को एक नए मायऑब्जेक्ट में सेट करने के लिए, आपको ऑब्जेक्ट्स [इंडेक्स] को इंगित करने की आवश्यकता है, जिसे ऑब्जेक्ट्स [इंडेक्स] का उपयोग करके ही किया जा सकता है।

छवि: (मेरे भयानक रंग कौशल: डी)

enter image description here

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

ओ ए 1 या बी 1, लेकिन सी 1 या सी 2 का संदर्भ नहीं देता है। जब आप new ... कहते हैं, तो यह एक नई वस्तु बनाएगा और वहां ओ रखेगा (उदाहरण के लिए, स्लॉट ए 3 में)। यह ए 1 या बी 1 को प्रभावित नहीं करेगा।

मुझे बताएं कि क्या मैं चीजों को थोड़ा सा साफ़ कर सकता हूं।

+0

निश्चित रूप से, यह sence बनाता है। तो पहले उदाहरण में, ओ एक सी ++ पॉइंटर की तरह थोड़ा सा है, जिसमें यह स्वयं एक चर है, और इस प्रकार यह मान किसी अन्य चर का पता है। तो जब इसे किसी भी चीज़ को निर्दिष्ट करते हैं, तो वैरिएबल, जो इंगित कर रहा है उसके बजाए, सेट किया गया है। धन्यवाद! – rhughes

+0

बिल्कुल: डी ++ के विपरीत, जावा के पॉइंटर्स नियंत्रण और इस तरह के रास्ते में बहुत कुछ नहीं है। चर मेमोरी में संदर्भ स्थान, और '=' उन्हें दोबारा संदर्भित करता है। आप एक नया वैरिएबल नहीं बना सकते जहां आपने संदर्भित किया था। हालांकि, आप इस चर को बदल सकते हैं। यदि 'o' पहले ही प्रारंभ हो चुका है और' o.x' एक फ़ील्ड है, तो आप 'o.x' अंक कहां बदल सकते हैं, इस प्रकार' o.x' को पुन: असाइन कर सकते हैं। –

3

पहले एक आवंटन नहीं किया गया है वस्तुओं क्योंकि foreach छोरों एक संग्रह में तत्वों से अधिक पुनरावृति।

जब आप foreach लूप दर्ज करते हैं तो आपके संग्रह में कोई तत्व नहीं है, यह आकार 6 के लिए शुरू की गई एक खाली सरणी है, इसलिए आपके सरणी में कोई ऑब्जेक्ट नहीं जोड़ा जाएगा।

ही, ध्यान दें कि भले ही आप सरणी में तत्वों था foreach पाश उनमें से शीर्ष पर निर्दिष्ट नहीं करेंगे:

o = new MyObject(); 

मूल रूप से इसका मतलब है o करने के लिए MyObject का एक नया उदाहरण आवंटित है, लेकिन o ही नहीं है सरणी का हिस्सा objects यह केवल एक अस्थायी कंटेनर है जो सरणी के तत्वों को पुन: सक्रिय करने के लिए उपयोग किया जाता है, लेकिन इस मामले में, कोई भी नहीं है।

+0

यह वास्तव में खाली नहीं है, इसमें सिर्फ 6 नल हैं। अन्यथा, अच्छा जवाब। +1 –

+0

इस अर्थ में खाली है कि इसके अंदर 'MyObject' के कोई तत्व नहीं हैं। –

+0

मुझे लगता है कि हम एक ही बात अलग-अलग शब्दों में कह रहे हैं। –

8

संक्षिप्त उत्तर: हाँ, एक प्रतिलिपि की तरह कुछ है।

विस्तृत उत्तर: जावा foreach पाश आप पोस्ट के लिए

MyObject objects[] = new MyObject[6]; 

Iterator<MyObject> it = objects.iterator(); 
while (it.hasNext()) { 
    MyObject o = it.next(); 
    // The previous three lines were from the foreach loop 

    // Your code inside the foreach loop 
    o = new MyObject(); 
} 

रूप desugared संस्करण शो वाक्यात्मक चीनी है एक foreach पाश अंदर कुछ के बराबर एक संदर्भ की स्थापना की सामग्री को नहीं बदलता है सरणी।

2

ऑब्जेक्ट्स केवल "कॉपी" होते हैं जब आप स्पष्ट रूप से बताते हैं कि आप किसी ऑब्जेक्ट को क्लोन करना चाहते हैं (और यह ऑब्जेक्ट स्पष्ट रूप से क्लोनिंग सुविधा लागू करता है)।

आप संदर्भ और नाम भ्रमित लगते हैं।

पहले उदाहरण में, एक foreach के अंदर, स्थानीय o चर मेमोरी के क्षेत्र को संदर्भित करता है objects से कुछ ऑब्जेक्ट संग्रहीत किया जाता है। जब आप o = new MyObject() कर रहे हैं, तो स्मृति के किसी अन्य क्षेत्र में एक नया MyObject प्रारंभ किया गया है, और फिर o संदर्भ स्मृति के इस नए क्षेत्र को इंगित करने के लिए फिर से लिखा गया है।

दूसरे उदाहरण में, objects[i] = new MyObject() लिखकर, आप कह रहे हैं कि objects[i] संदर्भ को फिर से लिखा जाना चाहिए, कुछ स्थानीय o चर नहीं।

4

मैंने यह स्पष्ट करने के लिए प्रत्येक उदाहरण में एक टिप्पणी जोड़ा कि क्या हो रहा है।

पहले उदाहरण:

MyObject objects[] = new MyObject[6]; 
for(MyObject o: objects) { 

    // Construct a new object of type MyObject and assign a reference to it into 
    // the iteration variable o. This has no lasting effect, because the foreach 
    // loop will automatically assign the next value into the iteration variable 
    // in the the next iteration. 
    o = new MyObject(); 
} 

दूसरा उदाहरण:

MyObject objects[] = new MyObject[6]; 
for(int i = 0; i < objects.length; i++) { 

    // Construct a new object of type MyObject and store a reference to it into the 
    // i-th slot in array objects[]: 
    objects[i] = new MyObject(); 
} 
+0

यह बिल्कुल संकलित नहीं होगा, क्योंकि जावा में कोई कीवर्ड नहीं है, आपको एक कोलन (:) वहां रखना चाहिए। –

+0

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

+0

जो भी -1 इगोर को कहना चाहिए कि उन्होंने ऐसा क्यों किया। यदि आप सुधार के लिए स्पष्टीकरण नहीं देते हैं तो नकारात्मक प्रतिक्रिया का कोई उपयोग नहीं होता है। इगोर, मुझे संदेह है कि आप गहराई की कमी के कारण -1 थे। –

0

पहली बात मैं उल्लेख करना चाहते हैं कि गैर शून्य लंबाई सरणियों हमेशा foreach पाश

for(MyObject o in objects) 
अंदर mutable.And हैं

प्रत्येक पुनरावृत्ति में यह क्या करता है यह निम्नानुसार काम करता है।

o = objects[0] // first iteration 
o = objects[1] // 2nd iteration 

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

ObjeMyObject objects[] = new MyObject[6]; 
MyObject o = Object[0]; 
0 = new MyObject(); 

लेकिन आपकी मूल वस्तुएं [0] अभी भी एक शून्य वस्तु को इंगित करती हैं।

0

हर बार जब आप "नया" ऑपरेटर का उपयोग करते हैं तो JVM एक नया उदाहरण बनाएगा और इसे असाइनमेंट ऑपरेटर के बाएं हाथ की ओर से सौंपा जाएगा। यह प्रत्येक लूप या लूप के लिए कोई फर्क नहीं पड़ता। (: ऑब्जेक्ट MyObject ओ) हे एक बार ही नहीं MyObject यह instantiated नहीं किया जाएगा हो जाएगा और वस्तु सरणी से मान होंगे हे में नकल रखने

O = Object[0] 
O = Object[1] 
O = Object[2] 
O = Object[3] 
O = Object[4] 
O = Object[5] 
की तरह बनाया जाएगा के लिए प्रत्येक पाश के लिए में

हमें काउंटर को बढ़ाने की देखभाल करने की आवश्यकता नहीं है, प्रत्येक लूप की सुंदरता है।

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