কীভাবে সঠিকভাবে ক্লোন পদ্ধতি ওভাররাইড করবেন?


114

আমার কোনও অবজেক্টে একটি গভীর ক্লোন প্রয়োগ করতে হবে যার কোনও সুপারক্লাস নেই।

CloneNotSupportedExceptionসুপারক্লাস (যা Object) নিক্ষেপ করা চেকটি পরিচালনা করার সর্বোত্তম উপায় কী ?

একজন সহকর্মী আমাকে নিম্নলিখিত পদ্ধতিতে এটি পরিচালনা করার পরামর্শ দিয়েছেন:

@Override
public MyObject clone()
{
    MyObject foo;
    try
    {
        foo = (MyObject) super.clone();
    }
    catch (CloneNotSupportedException e)
    {
        throw new Error();
    }

    // Deep clone member fields here

    return foo;
}

এটি আমার কাছে ভাল সমাধানের মতো বলে মনে হচ্ছে তবে আমি অন্তর্ভুক্ত করতে পারে এমন অন্য কোনও অন্তর্দৃষ্টি আছে কিনা তা দেখার জন্য আমি এটি স্ট্যাকওভারফ্লো সম্প্রদায়ের কাছে ফেলে দিতে চেয়েছিলাম। ধন্যবাদ!


6
যদি আপনি জানেন যে পিতামাত্ত শ্রেণি প্রয়োগ করে Cloneableতবে AssertionErrorকেবল একটি সরল পরিবর্তে একটি নিক্ষেপ করা Errorকিছুটা বেশি উদ্বেগজনক।
অ্যান্ড্রু ডাফি

সম্পাদনা: আমি বরং ক্লোন () ব্যবহার করব না, তবে প্রকল্পটি ইতিমধ্যে এর উপর ভিত্তি করে তৈরি হয়েছে এবং এটি এই মুহুর্তে সমস্ত রেফারেন্সগুলি রিফ্যাক্টর করার উপযুক্ত হবে না।
কুগা

বুলেট কামড়ানোর চেয়ে এখনকার চেয়ে বরং ভাল (ভাল, যদি না আপনি কেবল উত্পাদন হিট করবেন)।
টম হাটিন -

এটি শেষ না হওয়া পর্যন্ত আমাদের সময়সূচীতে দেড় মাস বাকি রয়েছে। আমরা সময়কে ন্যায়সঙ্গত করতে পারি না।
কুগা

আমি মনে করি এই সমাধানটি নিখুঁত। এবং ক্লোন ব্যবহার করা খারাপ মনে করবেন না। আপনার যদি এমন কোনও শ্রেণি থাকে যা পরিবহন বস্তু হিসাবে ব্যবহৃত হয় এবং এতে কেবল স্ট্রিং এবং এনামসের মতো প্রাইমটিভ এবং অপরিবর্তনীয় জিনিস থাকে তবে ক্লোন ব্যতীত অন্য সমস্ত কিছু কূটনৈতিক কারণে সম্পূর্ণ সময় নষ্ট হবে। ক্লোন কী করে এবং কী না তা কেবল মনে রাখবেন! (কোনও গভীর ক্লোনিং নেই)
টমবোলক

উত্তর:


125

আপনি একেবারে ব্যবহার করতে হবে clone? বেশিরভাগ লোক সম্মত হন যে জাভা cloneভেঙে গেছে।

নকশায় জোশ ব্লচ - কপি নির্মাণকারী বনাম ক্লোনিং

আপনি যদি আমার বইটিতে ক্লোনিং সম্পর্কিত আইটেমটি পড়ে থাকেন, বিশেষত আপনি যদি লাইনের মধ্যে পড়ে থাকেন তবে আপনি বুঝতে পারবেন যে আমি মনে করি cloneগভীরভাবে ভেঙে গেছে। [...] এটি লজ্জাজনক যা Cloneableভেঙে গেছে, তবে এটি ঘটে।

আপনি তার বইয়ে বিষয়ে আরো আলোচনা পড়তে পারে ওভাররাইড: কার্যকরী জাভা 2nd সংস্করণ, আইটেম 11 clonejudiciously । তিনি পরিবর্তে একটি অনুলিপি নির্মাণকারী বা অনুলিপি কারখানা ব্যবহার করার পরামর্শ দেন।

তিনি কীভাবে পৃষ্ঠাগুলির পাতাগুলি লিখতে চেয়েছিলেন, যদি আপনার মনে হয় আপনার অবশ্যই প্রয়োগ করা উচিত clone। কিন্তু তিনি এটি দিয়ে বন্ধ করেছেন:

এই সমস্ত জটিলতা কি আসলেই প্রয়োজনীয়? কদাচ। যদি আপনি প্রয়োগ করে এমন কোনও শ্রেণি প্রসারিত করেন Cloneableতবে ভাল আচরণের cloneপদ্ধতিটি প্রয়োগ করা ছাড়া আপনার কাছে বিকল্প নেই । অন্যথায়, আপনি অবজেক্ট অনুলিপি করার বিকল্প উপায় সরবরাহ করা বা কেবল ক্ষমতা সরবরাহ না করার চেয়ে ভাল

জোর তার ছিল, আমার নয়।


যেহেতু আপনি স্পষ্ট করে দিয়েছিলেন যে বাস্তবায়নের পরিবর্তে আপনার কাছে খুব কম উপায় আছে clone, তাই আপনি এই ক্ষেত্রে যা করতে পারেন তা এখানে: নিশ্চিত করুন MyObject extends java.lang.Object implements java.lang.Cloneable। যদি সেই ক্ষেত্রে, তাহলে আপনি গ্যারান্টি পারেন যে আপনি হবে কখনও একটি ধরা CloneNotSupportedException। কারও AssertionErrorকারও পরামর্শ অনুসারে ছুড়ে দেওয়া যুক্তিসঙ্গত বলে মনে হয়, তবে আপনি এমন একটি মন্তব্যও যুক্ত করতে পারেন যা ব্যাখ্যা করে যে কেন এই বিশেষ ক্ষেত্রে ক্যাচ ব্লকটি কখনই প্রবেশ করা হবে না ।


বিকল্প হিসাবে, অন্যরা যেমন পরামর্শ দিয়েছে, আপনি সম্ভবত cloneকল না করে প্রয়োগ করতে পারবেন super.clone


1
দুর্ভাগ্যক্রমে, ক্লোন পদ্ধতিটি ব্যবহার করে এই প্রকল্পটি ইতিমধ্যে লেখা হয়েছে, অন্যথায় আমি একেবারেই এটি ব্যবহার করব না। আমি সম্পূর্ণরূপে আপনার সাথে একমত হই যে জাভার ক্লোনটি বাস্তবায়নের ফাক্ট্তা।
কুগা

5
যদি কোনও ক্লাস এবং এর সমস্ত সুপারক্লাসগুলি super.clone()তাদের ক্লোন পদ্ধতিগুলির মধ্যে কল করে তবে একটি সাবক্লাস সাধারণত তখনই ওভাররাইড করতে পারে clone()যদি এটিতে নতুন ক্ষেত্র যুক্ত হয় যার বিষয়বস্তু ক্লোন করার প্রয়োজন হবে। যদি কোনও সুপারক্লাস newপরিবর্তে ব্যবহার করে super.clone()তবে সমস্ত উপশ্রেণী অবশ্যই clone()তাদের নতুন ক্ষেত্র যুক্ত করবে কিনা তা ওভাররাইড করতে হবে ।
সুপারক্যাট

56

কখনও কখনও অনুলিপি নির্মাণকারী আরও কার্যকর করা:

public MyObject (MyObject toClone) {
}

এটি আপনাকে পরিচালনা করার ঝামেলা বাঁচায় CloneNotSupportedException, finalক্ষেত্রগুলির সাথে কাজ করে এবং আপনাকে ফিরে আসার ধরন সম্পর্কে চিন্তা করতে হবে না।


11

আপনার কোডটি যেভাবে কাজ করে তা এটি লেখার "ক্যানোনিকাল" পদ্ধতির খুব কাছে। AssertionErrorযদিও আমি ধরা পড়ার মধ্যেই ফেলে দেব । এটি ইঙ্গিত দেয় যে সেই লাইনটি কখনই পৌঁছানো উচিত নয়।

catch (CloneNotSupportedException e) {
    throw new AssertionError(e);
}

কেন এটি খারাপ ধারণা হতে পারে তার জন্য @ পলিজেলব্রিকেন্টস এর উত্তর দেখুন।
কার্ল রিখটার

@ কার্ল রিখটার আমি তাদের উত্তর পড়েছি। Cloneableকার্যকর জাভাতে বর্ণিত হিসাবে এটি সাধারণভাবে একটি ভাঙা ধারণা ছাড়া এটি একটি খারাপ ধারণা বলে না । ওপি ইতিমধ্যে প্রকাশ করেছে যে তাদের ব্যবহার করতে হবে Cloneable। সুতরাং আমার উত্তরটি কীভাবে আরও উত্তম হতে পারে তা আমি একেবারেই জানিনা, সম্ভবত এটি সরাসরি মুছে ফেলা ছাড়া।
ক্রিস জেস্টার-ইয়ং

9

দুটি ক্ষেত্রে আছে যেখানে CloneNotSupportedExceptionনিক্ষেপ করা হবে:

  1. ক্লোন করা ক্লাসটি প্রয়োগ করা হয় না Cloneable(ধরে নিই যে প্রকৃত ক্লোনিং শেষ পর্যন্ত Objectক্লোন পদ্ধতিতে স্থগিত হয় )। আপনি ক্লাসটি প্রয়োগে এই পদ্ধতিটি লিখছেন Cloneable, তা কখনই ঘটবে না (যেহেতু কোনও উপ-শ্রেণি এটি যথাযথভাবে উত্তরাধিকারী হবে)।
  2. ব্যতিক্রম স্পষ্টভাবে একটি বাস্তবায়ন দ্বারা নিক্ষেপ করা হয় - সুপারক্লাস হয় এটি একটি সাবক্লাসে ক্লোনিবিলিটি রোধ করার প্রস্তাবিত উপায় Cloneable

পরের কেসটি আপনার ক্লাসে ঘটতে পারে না (যেহেতু আপনি tryব্লকটিতে সরাসরি সুপারক্লাসের পদ্ধতিটি কল করছেন , এমনকি সাবক্লাস কলিং থেকে আহবান করা হলেও super.clone()) এবং প্রাক্তনটিকে আপনার ক্লাসটি পরিষ্কারভাবে প্রয়োগ করা উচিত নয় Cloneable

মূলত, আপনার অবশ্যই ত্রুটিটি লগ করা উচিত, তবে এই বিশেষ পরিস্থিতিতে এটি কেবল তখনই ঘটবে যদি আপনি আপনার শ্রেণীর সংজ্ঞাটি গণ্ডগোল করেন। সুতরাং এটি NullPointerException(বা অনুরূপ) এর পরীক্ষিত সংস্করণের মতো আচরণ করুন - আপনার কোডটি কার্যকর থাকলে এটি কখনও ছুঁড়ে ফেলা হবে না।


অন্যান্য পরিস্থিতিতে আপনি এই পরিণাম জন্য প্রস্তুত করা করতে হবে - যে কোন গ্যারান্টি একটি প্রদত্ত বস্তু আছে হয় cloneable, তাই যখন ব্যতিক্রম সংক্রামক এই অবস্থার উপর নির্ভর করে (বিদ্যমান বস্তুর সঙ্গে অবিরত যথাযথ ব্যবস্থা গ্রহণ করা উচিত, একটি বিকল্প ক্লোনিং কৌশল নেওয়া উদাহরণস্বরূপ সিরিয়ালাইজ-ডিসরিয়ালাইজ করুন, IllegalParameterExceptionযদি আপনার পদ্ধতির ক্লোনযোগ্য ইত্যাদি দ্বারা প্যারামিটারের প্রয়োজন হয় তবে একটি নিক্ষেপ করুন )

সম্পাদনা : যদিও সামগ্রিকভাবে আমার উল্লেখ করা উচিত যে হ্যাঁ, clone()সঠিকভাবে বাস্তবায়ন করা কঠিন এবং কলকারীর পক্ষে রিটার্নের মান তারা যা চান তা দ্বিগুণ, তাই যখন আপনি গভীর বনাম অগভীর ক্লোনগুলি বিবেচনা করেন তখন তা দুষ্কৃত হয়। পুরো জিনিসটি পুরোপুরি এড়ানো এবং অন্য প্রক্রিয়াটি ব্যবহার করা প্রায়শই ভাল।


যদি কোনও অবজেক্ট কোনও সার্বজনীন ক্লোনিং পদ্ধতি প্রকাশ করে তবে যে কোনও উত্পন্ন বস্তু যা এটি সমর্থন করে না তা লিসকভ সাবস্টিটিউশন নীতি লঙ্ঘন করবে। একটি ক্লোনিং পদ্ধতি সুরক্ষিত থাকে তাহলে আমি মনে করি হবে এটি সঠিক ধরন উপস্থাপন করা পদ্ধতি ব্যতীত অন্য কিছু দিয়ে ছায়া এমনকি কল করার চেষ্টা থেকে একটি উপশ্রেণী প্রতিরোধ ভাল হবে super.clone()
সুপারক্যাট

5

গভীর অনুলিপি তৈরি করতে সিরিয়ালাইজেশন ব্যবহার করুন । এটি দ্রুততম সমাধান নয় তবে এটি ধরণের উপর নির্ভর করে না।


আমি ইতিমধ্যে জিএসওএন ব্যবহার করছিলাম এটি বিবেচনা করে এটি একটি দুর্দান্ত এবং সুস্পষ্ট সমাধান ছিল।
জ্যাকব তাবাক

3

আপনি সুরক্ষিত অনুলিপি নির্মাণকারী এর মতো প্রয়োগ করতে পারেন:

/* This is a protected copy constructor for exclusive use by .clone() */
protected MyObject(MyObject that) {
    this.myFirstMember = that.getMyFirstMember(); //To clone primitive data
    this.mySecondMember = that.getMySecondMember().clone(); //To clone complex objects
    // etc
}

public MyObject clone() {
    return new MyObject(this);
}

3
এটি বেশিরভাগ সময় কাজ করে না। আপনি যদি clone()ফিরে getMySecondMember()না আসা বস্তুটির কাছে কোনও public cloneপদ্ধতি না করে কল করতে পারবেন না ।
বহুবিশ্লেষকরা

স্পষ্টতই, আপনি ক্লোন করতে সক্ষম হতে চান এমন প্রতিটি বস্তুর উপর আপনাকে এই প্যাটার্নটি প্রয়োগ করতে হবে বা প্রতিটি সদস্যকে গভীরভাবে ক্লোন করার জন্য অন্য কোনও উপায় খুঁজে বের করতে হবে।
ডল্ফ

হ্যাঁ, এটি একটি প্রয়োজনীয় প্রয়োজন।
বহুবিশ্বেষক

1

এখানে বেশিরভাগ উত্তর যেমন বৈধ, তবুও আপনাকে জানাতে হবে যে আপনার সমাধানটি আসল জাভা এপিআই বিকাশকারীরা কীভাবে এটি করে। (হয় জোশ ব্লচ বা নিল গেরোটার)

এখানে ওপেনজেডিকে, অ্যারেলিস্ট ক্লাসের একটি নির্যাস রয়েছে:

public Object clone() {
    try {
        ArrayList<?> v = (ArrayList<?>) super.clone();
        v.elementData = Arrays.copyOf(elementData, size);
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
}

যেমন আপনি লক্ষ্য করেছেন এবং অন্যরা উল্লেখ CloneNotSupportedExceptionকরেছেন , আপনি যদি ঘোষণা করেন যে আপনি Cloneableইন্টারফেসটি বাস্তবায়ন করেছেন তবে নিক্ষেপ করার প্রায় কোনও সম্ভাবনা নেই ।

এছাড়াও, আপনি যদি ওভাররাইড হওয়া পদ্ধতিতে নতুন কিছু না করেন তবে পদ্ধতিটি ওভাররাইড করার দরকার নেই। আপনাকে কেবল যখন এটিকে অতিরিক্ত ক্রিয়াকলাপ করতে হবে বা আপনাকে এটি সর্বজনীন করতে হবে তখন আপনার এটিকে ওভাররাইড করতে হবে।

শেষ পর্যন্ত, এড়াতে এবং এটি অন্য কোনও উপায়ে ব্যবহার করা ভাল।


0
public class MyObject implements Cloneable, Serializable{   

    @Override
    @SuppressWarnings(value = "unchecked")
    protected MyObject clone(){
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        try {
            ByteArrayOutputStream bOs = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bOs);
            oos.writeObject(this);
            ois = new ObjectInputStream(new ByteArrayInputStream(bOs.toByteArray()));
            return  (MyObject)ois.readObject();

        } catch (Exception e) {
            //Some seriouse error :< //
            return null;
        }finally {
            if (oos != null)
                try {
                    oos.close();
                } catch (IOException e) {

                }
            if (ois != null)
                try {
                    ois.close();
                } catch (IOException e) {

                }
        }
    }
}

সুতরাং আপনি এটি কেবল ফাইল সিস্টেমে লিখেছেন এবং অবজেক্টটি ফিরে পড়েছেন। ঠিক আছে, এটি কি ক্লোন পরিচালনা করার সেরা পদ্ধতি? এসও সম্প্রদায়ের যে কেউ এই পদ্ধতির বিষয়ে মন্তব্য করতে পারেন? আমার ধারণা, এটি অযৌক্তিকভাবে ক্লোনিং এবং সিরিয়ালাইজেশন - দুটি সম্পূর্ণ ভিন্ন ধারণা ties এ সম্পর্কে অন্যেরা কী বলবে তা দেখার জন্য আমি অপেক্ষা করব।
সৌরভ পাতিল

2
এটি ফাইল সিস্টেমে নয়, এটি মূল মেমোরিতে রয়েছে (বাইটআরআউটপুট স্ট্রিম)। গভীরভাবে নেস্টেড বস্তুর জন্য এর সমাধানটি ভালভাবে কাজ করে। বিশেষত যদি আপনার এটির প্রায়শই প্রয়োজন হয় না, যেমন ইউনিট পরীক্ষায়। যেখানে কর্মক্ষমতা মূল লক্ষ্য নয়।
অ্যালেক্সওয়েন

0

ক্লোনেবলের জাভা বাস্তবায়ন ভেঙে যাওয়ার অর্থ এই নয় যে আপনি নিজের একটি তৈরি করতে পারবেন না।

যদি ওپی আসল উদ্দেশ্যটি একটি গভীর ক্লোন তৈরি করা হত, আমি মনে করি যে এটির মতো একটি ইন্টারফেস তৈরি করা সম্ভব:

public interface Cloneable<T> {
    public T getClone();
}

তারপরে এটি প্রয়োগের জন্য উল্লিখিত প্রোটোটাইপ কনস্ট্রাক্টরটি ব্যবহার করুন:

public class AClass implements Cloneable<AClass> {
    private int value;
    public AClass(int value) {
        this.vaue = value;
    }

    protected AClass(AClass p) {
        this(p.getValue());
    }

    public int getValue() {
        return value;
    }

    public AClass getClone() {
         return new AClass(this);
    }
}

এবং একটি ক্লাস অবজেক্ট ক্ষেত্র সহ অন্য শ্রেণি:

public class BClass implements Cloneable<BClass> {
    private int value;
    private AClass a;

    public BClass(int value, AClass a) {
         this.value = value;
         this.a = a;
    }

    protected BClass(BClass p) {
        this(p.getValue(), p.getA().getClone());
    }

    public int getValue() {
        return value;
    }

    public AClass getA() {
        return a;
    }

    public BClass getClone() {
         return new BClass(this);
    }
}

এইভাবে আপনি @ সাপ্রেস ওয়ার্নিংস বা অন্যান্য নকল কোডের প্রয়োজন ছাড়াই বিসি ক্লাসের ক্লাসের কোনও বিষয় সহজেই গভীর ক্লোন করতে পারবেন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.