क्यों क्लोन () विधि java.lang.Object में संरक्षित है?


जवाबों:


107

तथ्य यह है कि क्लोन संरक्षित है बेहद संदिग्ध है - जैसा कि तथ्य यह है कि इंटरफ़ेस cloneमें विधि घोषित नहीं की गई Cloneableहै।

यह डेटा की प्रतियां लेने के लिए विधि को बहुत बेकार बनाता है क्योंकि आप यह नहीं कह सकते :

if(a instanceof Cloneable) {
    copy = ((Cloneable) a).clone();
}

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

ISomething i = ...
if (i instanceof Cloneable) {
   //DAMN! I Need to know about ISomethingImpl! Unless...
   copy = (ISomething) i.getClass().getMethod("clone").invoke(i);
}

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


2
यदि ऑब्जेक्ट क्लोन करने योग्य नहीं है, तो ऑब्जेक्ट का क्लोन () CloneNotSupportedException को फेंक देगा। यदि आप सुपर कॉल करने जा रहे हैं तो आपको क्लोन करने योग्य होने की आवश्यकता है। () (जिसके परिणामस्वरूप Object.clone () कहा जा रहा है)। मैं यह नहीं देखता कि किसी वस्तु को क्रमिक रूप से कार्यान्वित किए बिना कैसे क्रमबद्ध किया जा सकता है।
स्टीव कू

1
"मुझे लगता है कि क्लोन करने योग्य का डिज़ाइन अब काफी हद तक एक गलती के रूप में माना जाता है।" [उद्धरण वांछित]
केविन पैंको

क्षमा करें - मैं इसका अर्थ यह नहीं लगा रहा था। मैं केवल यह कह रहा था कि "अच्छा" डिज़ाइन एक इंटरफ़ेस का विस्तार नहीं करना है Serializable- यह लागू करने के लिए निर्णय लेने के लिए है Serializable। मैं इसे बढ़ा रहा था Cloneable- यह ऐसा कुछ नहीं है जिसे एक इंटरफ़ेस का विस्तार करना चाहिए - लेकिन एक इंटरफ़ेस का कार्यान्वयन मुफ्त है Cloneable। मुसीबत यह है, यदि आपके पास इंटरफ़ेस प्रकार का पैरामीटर है, तो आप पूछते हैं कि क्या यह क्लोन करने योग्य है; लेकिन फिर आप वास्तव में इसे क्लोन नहीं कर सकते हैं!

6
@ केविन - जोश बलोच का प्रभावी जावा पीपी 45। "क्लोन करने योग्य इंटरफ़ेस का उद्देश्य वस्तुओं के लिए एक मिश्रित इंटरफ़ेस के रूप में था, ताकि वे क्लोनिंग की अनुमति दे सकें। दुर्भाग्य से यह इस उद्देश्य की पूर्ति करने में विफल है"
Oxbow_lakes

एक ही पृष्ठ पर: "यह इंटरफेस का अत्यधिक उपयोग है और किसी का अनुकरण नहीं किया जाना चाहिए" और "इंटरफ़ेस को लागू करने के लिए किसी वर्ग पर कोई प्रभाव पड़ता है, इसे और इसके सभी सुपरक्लासेस को एक काफी जटिल मानना ​​होगा ।"
अप्राप्य

30

क्लोन करने योग्य इंटरफ़ेस सिर्फ एक मार्कर है जो कह रहा है कि वर्ग क्लोन का समर्थन कर सकता है। यह विधि संरक्षित है क्योंकि आपको इसे ऑब्जेक्ट पर कॉल नहीं करना चाहिए, आप इसे सार्वजनिक कर सकते हैं (और चाहिए)।

सूर्य से:

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


जो ठीक है, जब तक आप मिश्रण में इंटरफेस नहीं लाते हैं - कोशिश करें और अनजान कार्यान्वयन को क्लोन करने का प्रयास करेंSet
oxbow_lakes

@oxbow_lakes: लेकिन शायद सेट के कुछ कार्यान्वयन क्लोन नहीं हैं
newacct

3
आप कुछ भी क्लोन नहीं कर सकते हैं जो क्लोन करने योग्य इंटरफ़ेस को लागू नहीं करता है - यह एक मार्कर है जो कहता है कि "यह वर्ग ठीक से क्लोन करने योग्य है" - बहुत ही सीरियल इंटरफ़ेस के समान है। वैसे, क्रमबद्धता के माध्यम से कक्षाओं को क्लोन करने का एक तरीका है जो अच्छी तरह से काम करता है - "java serialization क्लोन" जैसे कुछ।
बिल के

4
आप कुछ भी क्लोन नहीं कर सकते जो क्लोन करने योग्य इंटरफ़ेस को लागू नहीं करता है, लेकिन सिर्फ इसलिए कि कुछ क्लोन करने योग्य इंटरफ़ेस को लागू करता है इसका मतलब यह नहीं है कि आप इसे क्लोन कर सकते हैं।
माइकल मायर्स

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

7

cloneयह संरक्षित है क्योंकि यह कुछ ऐसा है जिसे अतिरंजित होना चाहिए ताकि यह वर्तमान वर्ग के लिए विशिष्ट हो। हालांकि यह एक सार्वजनिक cloneविधि बनाना संभव होगा, जो किसी भी वस्तु को इस सब पर क्लोन कर सकेगा, विशेष रूप से उस वर्ग के लिए लिखी गई विधि के रूप में अच्छा नहीं होगा जिसकी उसे आवश्यकता है।


लेकिन इसके लिए इसे संरक्षित क्यों किया जाता है?
Janusz

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

1
और जब मेरी बात के अनुसार इंटरफेस पर विचार करना बेकार है

ओवरराइड किया जाना चाहिए यह बहुत स्पष्ट नहीं है, तो यह अमूर्त होना चाहिए था और फिर ऑब्जेक्ट क्लास में नहीं होना चाहिए, मैं यह समझने की कोशिश कर रहा हूं कि ऐसा क्यों है।
कुमार अभिषेक

4

क्लोन विधि का किसी भी वस्तु पर सीधे उपयोग नहीं किया जा सकता है, यही कारण है कि इसे उपवर्ग द्वारा ओवरराइड करने का इरादा है।

बेशक यह सार्वजनिक हो सकता है और क्लोनिंग संभव नहीं होने पर केवल एक उपयुक्त अपवाद फेंक सकता है, लेकिन मुझे लगता है कि यह भ्रामक होगा।

जिस तरह से क्लोन को अभी लागू किया गया है उससे आपको लगता है कि आप क्लोन का उपयोग क्यों करना चाहते हैं, और आप अपनी वस्तु को क्लोन कैसे करना चाहते हैं।


2

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

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


वास्तव में डिफ़ॉल्ट कार्यान्वयन (ऑब्जेक्ट में) डॉक्स के अनुसार एक अपवाद फेंकता है ...
बिल K

2
नहीं, यह सिर्फ फेंक नहीं है। इसके JavaDoc से: "क्लास ऑब्जेक्ट के लिए विधि क्लोन एक विशिष्ट क्लोनिंग ऑपरेशन करता है। सबसे पहले, यदि इस ऑब्जेक्ट का वर्ग इंटरफ़ेस को क्लोन करने योग्य लागू नहीं करता है, तो एक CloneNotSupportedException को फेंक दिया जाता है। ध्यान दें कि सभी सरणियों को इंटरफ़ेस को लागू करने के लिए माना जाता है। अन्यथा, यह विधि इस ऑब्जेक्ट के वर्ग का एक नया उदाहरण बनाती है और इस ऑब्जेक्ट के संबंधित फ़ील्ड की सामग्री के साथ अपने सभी फ़ील्ड्स को इनिशियलाइज़ करती है, जैसे कि असाइनमेंट द्वारा; फ़ील्ड की सामग्री को स्वयं क्लोन नहीं किया जाता है। "
पावेल मिनावे

2

क्लोन के javadoc से।

* By convention, classes that implement this interface (cloneable) should override 
* <tt>Object.clone</tt> (which is protected) with a public method.
* See {@link java.lang.Object#clone()} for details on overriding this
* method.

* Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
* Therefore, it is not possible to clone an object merely by virtue of the
* fact that it implements this interface.  Even if the clone method is invoked
* reflectively, there is no guarantee that it will succeed.

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


2
आप प्रत्येक ऑब्जेक्ट पर क्लोन नहीं कह सकते , क्योंकि यह संरक्षित है!
पावेल मिनावे

2

IMHO यह इतना सरल है:

  • #clone गैर-क्लोन करने योग्य वस्तुओं पर नहीं बुलाया जाना चाहिए, इसलिए इसे सार्वजनिक नहीं किया जाता है
  • #cloneउपवर्गों द्वारा आह्वान किया जाता है Objectकि सही वर्ग की उथली प्रतिलिपि प्राप्त करने के लिए क्लोन करने योग्य लागू करें

उपवर्गों द्वारा कॉल करने योग्य तरीकों के लिए सही गुंजाइश क्या है, लेकिन अन्य वर्गों द्वारा नहीं?

यह है protected

Cloneableपाठ्यक्रम को लागू करने वाले वर्ग इस पद्धति को सार्वजनिक करेंगे ताकि इसे अन्य वर्गों से बुलाया जा सके।


0

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

इसलिए जो भी वर्ग क्लोन करने योग्य हैं वे ऑब्जेक्ट क्लास के क्लोन () पद्धति का उपयोग कर सकते हैं।

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


-2

हां, वही समस्या जो मुझे मिली। लेकिन मैं इस कोड को लागू करके इसे हल करता हूं

public class Side implements Cloneable {
    public Side clone() {

        Side side = null;
        try {
            side = (Side) super.clone();
        } catch (CloneNotSupportedException e) {
            System.err.println(e);
        }
        return side;
    }
}

जैसा पहले किसी ने कहा था।


1
CloneNotSupportedException चेक किए गए अपवाद का एक और उदाहरण है जिसे अनियंत्रित किया जाना चाहिए (अर्थात, यह RuntimeException का विस्तार करना चाहिए, अपवाद नहीं)। हालाँकि, क्लास साइड में क्लोन () क्लोन क्लोन करने योग्य है और इसलिए कभी भी CloneNotSupportedException को नहीं फेंकेगा, Side.clone () को अभी भी अपवाद को पकड़ना या घोषित करना होगा। यह सिर्फ क्लोन () पद्धति के लिए शानदार अपवाद हैंडलिंग शोर जोड़ता है।
डेरेक महार

-2

खैर, यह भी सूर्य डेवलपर्स केवल मानव हैं, और उन्होंने वास्तव में क्लोन पद्धति को संरक्षित करने के लिए लागू करने के लिए बहुत बड़ी गलती की थी, वही गलती उन्होंने ArrayList में गैर-कामकाजी क्लोन विधि को लागू किया! तो, सामान्य तौर पर, क्लोन विधि के बारे में भी अनुभवी जावा प्रोग्रामर की बहुत गहरी गलतफहमी मौजूद है।

हालाँकि, मैंने हाल ही में अपनी सभी सामग्री के साथ किसी भी वस्तु को कॉपी करने के लिए एक तेज़ और आसान समाधान पाया है, चाहे वह कैसे बनाया गया हो और इसमें क्या शामिल है, मेरा जवाब यहां देखें: Object.clone () का उपयोग करने में बग


-3

फिर से, जावा JDK फ्रेमवर्क शानदार सोच दिखाता है:

क्लोन करने योग्य इंटरफ़ेस में "सार्वजनिक टी क्लोन () नहीं है;" विधि क्योंकि यह एक विशेषता की तरह अधिक कार्य करता है (जैसे। Serializable) जो एक उदाहरण को क्लोन करने की अनुमति देता है।

इस डिज़ाइन में कुछ भी गलत नहीं है क्योंकि:

  1. Object.clone () वह नहीं करेगा जो आप अपने कस्टम-परिभाषित वर्ग के साथ चाहते हैं।

  2. यदि आपके पास माइक्लास लागू है क्लोन करने योग्य => आप "सार्वजनिक MyClass क्लोन (") के साथ क्लोन () को अधिलेखित करते हैं।

  3. यदि आपके पास MyInterface का विस्तार करने योग्य है और MyInterface को लागू करने वाले कुछ MyClasses: बस "सार्वजनिक MyInterface क्लोन ();" इंटरफ़ेस में और MyInterface ऑब्जेक्ट्स का उपयोग करने वाली प्रत्येक विधि उन्हें क्लोन करने में सक्षम होगी, कोई फर्क नहीं पड़ता कि उनका MyClass- वर्ग।


2
यदि आपके वर्ग को विरासत में प्राप्त होने वाली आपकी क्लोन श्रेणी का कार्यान्वयन लागू होना चाहिए, तो तब तक सुरक्षित रहेगा जब तक कि आपके आधार वर्ग के कार्यान्वयन सुरक्षित क्लोन तरीके प्रदान नहीं करते। इसके अलावा, यह विधि / विशेषता के बिना एक इंटरफ़ेस के लिए असामान्य डिज़ाइन स्थिति की तरह है। यह इंटरफ़ेस क्लास को क्लोन लागू करने के लिए बाध्य नहीं करता है।
प्रप 19
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.