2009-05-06 14 views
61

जावा एक कॉपी कन्स्ट्रक्टर का समर्थन क्यों नहीं करता है जैसे सी ++ में?जावा में एक कॉपी कन्स्ट्रक्टर क्यों नहीं है?

+0

ये कुछ महान स्पष्टीकरण हैं, सभी के लिए धन्यवाद! – Cuga

+0

यह भी पढ़ें "कॉपी कन्स्ट्रक्टर के साथ क्या गलत है? क्लोनबल इंटरफ़ेस का उपयोग क्यों करें?" http://stackoverflow.com/questions/388304/whats-wrong-with-copy-constructors-why-use-cloneable-interface –

उत्तर

117

जावा करता है। उन्हें सिर्फ इसलिए नहीं कहा जाता है कि वे सी ++ में हैं और मुझे संदेह है कि यह आपका असली सवाल है। कि उदाहरण में

Blah b2 = b1; 

क्लोनिंग/नकल बस बनाता है:

public class Blah { 
    private int foo; 

    public Blah() { } // public no-args constructor 
    public Blah(Blah b) { foo = b.foo; } // copy constructor 
} 

अब सी ++ परोक्ष प्रतिलिपि निर्माता इस तरह के एक बयान के साथ कॉल करेंगे:

सबसे पहले, एक प्रति निर्माता से अधिक कुछ भी नहीं है जावा में कोई समझ नहीं है क्योंकि सभी बी 1 और बी 2 संदर्भ हैं और मूल्य वस्तुएं नहीं हैं जैसे कि वे सी ++ में हैं। सी ++ में वह कथन वस्तु के राज्य की एक प्रति बनाता है। जावा में यह बस संदर्भ की प्रतिलिपि बनाता है। ऑब्जेक्ट की स्थिति की प्रतिलिपि बनाई गई नहीं है, इसलिए कॉपी कन्स्ट्रक्टर को स्पष्ट रूप से कॉल करने का कोई मतलब नहीं है।

और यह वास्तव में इसके लिए है।

+18

+1। जबकि हम में से बाकी वस्तु पदानुक्रमों के बारे में नाभि लग रहे थे, आप सीधे वाक्यविन्यास में कटौती करते थे - और शायद आपने ओपी के * वास्तविक * प्रश्न का उत्तर दिया था। –

+1

यह एक उत्कृष्ट स्पष्टीकरण है। बहुत बहुत धन्यवाद! – Cuga

+1

आप असाइनमेंट को संपादित करना चाहते हैं; आप स्वयं को बी 2 असाइन कर रहे हैं। इसके अलावा "राज्यक्षेत्रों की तरह" गलत स्थान पर एक जगह है। –

1

मान लीजिए कि उन्होंने अनुमान लगाया है कि आप इसके बजाय क्लोन() विधि बना सकते हैं?

8

मुझे लगता है कि इसका उत्तर बहुत दिलचस्प है।

एक के लिए, मेरा मानना ​​है कि जावा में सभी ऑब्जेक्ट्स ढेर पर हैं, और जब आपके पास पॉइंटर्स नहीं हैं, तो आपके पास "संदर्भ" हैं। संदर्भों में प्रतिलिपि symantics है और जावा आंतरिक रूप से संदर्भ संख्याओं का ट्रैक रखता है ताकि उसके कचरा कलेक्टर जानता है कि इससे छुटकारा पाने के लिए क्या सुरक्षित है।

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

 

+2

मैं सहमत हूं। कॉपी कन्स्ट्रक्टर वास्तव में सी ++ में मेमोरी प्रबंधन के मुद्दों को संबोधित कर रहा है। – alphazero

+0

डाउनवॉटेड क्योंकि: * जावा प्रतिलिपि (वस्तुओं के लिए) का उपयोग नहीं करता है। ऑब्जेक्ट पास करना ऑब्जेक्ट को क्लोन या कॉपी नहीं करता है, न ही यह संदर्भ गणना को संशोधित करता है - यह केवल संदर्भ पास करता है। * कॉपी सेमेन्टिक्स के बीच बहुत अधिक भ्रम, और तथ्य यह है कि उस ऑब्जेक्ट का संदर्भ कॉपी किया गया है। – Arafangion

+0

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

2

यह वह जगह है सिर्फ मेरी राय के बाद से वह यह है कि, सी में

कॉपी कंस्ट्रक्टर्स ++ मुख्य रूप से उपयोगी होते हैं जब आप भेज रहे हैं या मूल्य से कक्षाओं के उदाहरण लौटने (मुझे यकीन है कि एक उचित जवाब नहीं है कर रहा हूँ) जब प्रतिलिपि रचनाकार पारदर्शी रूप से सक्रिय होता है।

चूंकि जावा में सब कुछ संदर्भ द्वारा वापस किया जाता है, और वीएम गतिशील आवंटन की दिशा में तैयार है, वास्तव में एक प्रतिलिपि बनाने वाले की जटिलताओं के लिए औचित्य नहीं था।

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

0

ऐसा करता है। जब उथली प्रतियां ठीक होती हैं तो आपके पास [क्लोन()] (http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html#clone()) है और जब उन्हें आपको सी ++ की तरह गहरी प्रतिलिपि लागू नहीं करनी पड़ती है।

केवल वास्तविक अंतर यह है कि यह एक कन्स्ट्रक्टर के बजाए एक फैक्ट्री विधि है , लेकिन लचीलापन और टेस्टेबिलिटी के मामले में शायद यह एक अच्छी बात है।

0

मैं सी ++ प्रोग्रामर का अधिकतर नहीं हूं, लेकिन मुझे "तीन अमीगो" के बारे में एक नियम याद रखना प्रतीत होता है - कॉपी कन्स्ट्रक्टर, असाइनमेंट ऑपरेटर, और विनाशक। यदि आपके पास एक है, तो आपको शायद तीनों की आवश्यकता होगी।

तो शायद भाषा में विनाशक के बिना, वे एक कॉपी कन्स्ट्रक्टर शामिल नहीं करना चाहते थे? बस एक अनुमान।

+0

काफी नहीं है। सी ++ में, यह अधिक पसंद है: यदि आपको तीनों में से एक की आवश्यकता है (कहें, एक कॉपी कन्स्ट्रक्टर), तो आपको उस समय भी दो की आवश्यकता होगी, हालांकि आपको उस समय इसका एहसास नहीं हो सकता है। –

+1

इसके अलावा, अगर आपको उनकी आवश्यकता नहीं है, तो आपको उन्हें निजी घोषित करना चाहिए और उन्हें लागू नहीं करना चाहिए।यह संकलक को अपने स्वयं के "उथले" प्रतिलिपि संस्करण को प्रतिस्थापित करने से रोक देगा ... – dicroce

13
Bruce Eckel से

:

क्यों [एक प्रति निर्माता] C++ काम करता है और नहीं जावा?

कॉपी कन्स्ट्रक्टर सी ++ का एक मौलिक भाग है, क्योंकि यह स्वचालित रूप से किसी ऑब्जेक्ट की स्थानीय प्रति बनाता है। फिर भी उपरोक्त उदाहरण साबित करता है कि यह जावा के लिए काम नहीं करता है। क्यूं कर? जावा में हम जो कुछ भी उपयोग करते हैं वह हैंडल है, जबकि सी ++ में आपके पास हैंडल जैसी इकाइयां हो सकती हैं और आप सीधे ऑब्जेक्ट्स के चारों ओर पास कर सकते हैं। सी ++ प्रतिलिपि निर्माता यही है: जब आप ऑब्जेक्ट लेना चाहते हैं और इसे मूल्य से पास करना चाहते हैं, तो ऑब्जेक्ट को डुप्लिकेट करना। तो यह सी ++ में ठीक काम करता है, लेकिन आपको में ध्यान रखना चाहिए कि यह योजना जावा, में विफल हो जाती है, इसलिए इसका उपयोग न करें।

(मैं पूरे पृष्ठ को पढ़ने की सलाह - वास्तव में, here बजाय शुरू करते हैं।)

-1

जावा कॉपी निर्माता
नोट है: डेमो d2 = नए डेमो (डी 1) के बजाय, आप डेमो d2 = d1
मुख्य अंतर बी दो
/डब्ल्यू डेमो d2 = नया लिख ​​सकते हैं डेमो (डी 1) का मतलब नई वस्तु बनाई गई है और यह आबंटित स्मृति लेकिन
डेमो d2 है = d1 का तात्पर्य केवल संदर्भ चर जो वस्तु d1 का एक ही स्मृति पते का उपयोग करता बनाई गई है और इसलिए डी 2 आवंटित अलग स्मृति नहीं आवंटित।

प्रति निर्माता की सिंटेक्स:
नीचे उदाहरण पहले कॉपी निर्माता देखें बहुत आसान है :))
classname (पूर्णांक datafield) // सरल निर्माता
{
this.datafield = datafield;
}

classname (classname वस्तु)
{
datafield = वस्तु।datafield; //()
{

classname obj = नए classname कॉलिंग के लिए उदाहरण नीचे देखें
}
अब;

classname anotherObject = obj; // या classname anotherObject = नए classname (obj)

}

 

class demo 
{ 
    private int length; 

    private int breadth; 

    private int radius; 

    demo(int x,int y) 

    { 
     length=x; 
     breadth=y; 
    } 
    int area() 
    { 
     return length*breadth; 
    } 

    //Copy Constructor 
    demo(demo obj) 
    { 
     length=obj.length; 
     breadth=obj.breadth; 
    } 


    public static void main(String args[]) 
    { 
     demo d1=new demo(5,6); 
     demo d2=new demo(d1);//Invokes Copy Constructure 
     System.out.println("Area for d1 object="+d1.area()); 
     System.out.println("Area for d2 object="+d2.area()); 

    } 
} 

0

खैर, यह कर सकते हैं। यह सिर्फ अंतर्निहित नहीं बनाया गया है। अगर मुझे लगता है, तो शायद यह इस तथ्य से संबंधित है कि जावा ऑब्जेक्ट्स हमेशा ढेर-आवंटित होते हैं।

सी ++ में, डिफ़ॉल्ट प्रतिलिपि निर्माता एक सदस्यवार उथली प्रतिलिपि है। यदि एक वर्ग ढेर पर आवंटित स्मृति का मालिक है (कच्चे सूचक के माध्यम से), यह प्रतिलिपि मूल के साथ आंतरिक साझा करने का कारण बनता है, जो आप नहीं चाहते हैं।

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

भले ही उन्होंने एक डिफ़ॉल्ट प्रतिलिपि बनाने वाला एक डिफ़ॉल्ट प्रतिलिपि बनाया है, मुझे यकीन नहीं है कि यह विशेष रूप से उपयोगी होगा। न केवल आप सी ++ की तुलना में जावा में कम प्रतियां निष्पादित करते हैं, लेकिन आप हमेशा एक क्षेत्र को गहरी प्रतिलिपि बनाना नहीं चाहते हैं।

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

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

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