আপনি কীভাবে কোনও জিনিসের গভীর অনুলিপি তৈরি করবেন?


301

ডিপ অবজেক্ট কপি ফাংশন বাস্তবায়ন করা কিছুটা কঠিন। আসল অবজেক্টটি নিশ্চিত করার জন্য আপনি কী পদক্ষেপ গ্রহণ করেছেন এবং ক্লোন করা কোনও রেফারেন্স ভাগ করে নিচ্ছে?


4
কপি / ক্লোনিংয়ের জন্য ক্রিয়োর অন্তর্নির্মিত সমর্থন রয়েছে । এটি অবজেক্ট থেকে অবজেক্টে সরাসরি অনুলিপি করা হচ্ছে, অবজেক্ট-> বাইটস>> অবজেক্ট নয়।
নাটস

1
এখানে একটি সম্পর্কিত প্রশ্ন যা পরে জিজ্ঞাসা করা হয়েছিল: ডিপ ক্লোন ইউটিলিটি রিকোমেন্ডেশন
ব্র্যাড কাপিট

ক্লোনিং লাইব্রেরি ব্যবহার করে আমার জন্য দিনটি বাঁচা গেল! github.com/kostaskougios/cloning
গৌরব

উত্তর:


168

একটি নিরাপদ উপায় হ'ল অবজেক্টটিকে সিরিয়ালাইজ করা, তারপরে ডিসরিয়ালাইজ করা। এটি নিশ্চিত করে যে সমস্ত কিছু একেবারে নতুন রেফারেন্স।

কীভাবে এটি দক্ষতার সাথে করা যায় সে সম্পর্কে একটি নিবন্ধ এখানে

ক্যাভেটস: ক্লাসগুলির পক্ষে সিরিয়ালকরণকে ওভাররাইড করা যেমন নতুন উদাহরণ তৈরি হয় না , যেমন সিঙ্গেলটনের ক্ষেত্রে for এছাড়াও আপনার ক্লাসগুলি সিরিয়ালাইজযোগ্য না হলে অবশ্যই এটি কাজ করে না।


6
সচেতন থাকুন যে নিবন্ধে সরবরাহ করা ফাস্টবাইটিআরআউটপুট স্ট্রিম প্রয়োগ আরও কার্যকর হতে পারে। বাফার পূরণ করার সময় এটি একটি অ্যারেলিস্ট-স্টাইলের সম্প্রসারণ ব্যবহার করে তবে লিংকডলিস্ট-স্টাইলের সম্প্রসারণ পদ্ধতির ব্যবহার করা আরও ভাল। একটি নতুন 2x বাফার তৈরি এবং বর্তমান বাফারকে মেমকিপি-ইনগ করার পরিবর্তে, বাফারগুলির একটি লিঙ্কযুক্ত তালিকা বজায় রাখুন, বর্তমানটি পূরণ করার সাথে সাথে একটি নতুন যুক্ত করুন। আপনি যদি আপনার ডিফল্ট বাফার আকারের চেয়ে আরও বেশি ডেটা লেখার অনুরোধ পান তবে অনুরোধের মতোই বড় একটি বাফার নোড তৈরি করুন; নোডগুলির একই আকারের দরকার নেই।
ব্রায়ান হ্যারিস 16

: শুধু kryo ব্যবহার github.com/EsotericSoftware/kryo#copyingcloning বেঞ্চমার্ক slideshare.net/AlexTumanoff/serialization-and-performance
zengr

সিরিয়ালাইজেশন মাধ্যমে গভীর অনুলিপি ব্যাখ্যা করে একটি ভাল নিবন্ধ: javaworld.com/article/2077578/learn-java/…
বিজ্ঞাপন ইনফিনিটাম

@ ব্রায়ান হারিস লিঙ্ক করা তালিকাটি গতিশীল অ্যারের চেয়ে বেশি কার্যকর নয়। একটি গতিশীল অ্যারেতে উপাদান সন্নিবেশ করানো ধ্রুবক জটিলতা, যখন কোনও লিঙ্কযুক্ত তালিকায় সন্নিবেশ করা হয় রৈখিক জটিলতা
নরিল টেম্পেস্ট

কপিরাইট কনস্ট্রাক্টর পদ্ধতির চেয়ে ধীরে ধীরে সিরিয়ালাইজ ও ডিসিরিয়ালাইজেশন করা কীভাবে?
ওউল্যান্ড

75

কিছু লোক ব্যবহার বা ওভাররাইডিংয়ের কথা উল্লেখ করেছেন Object.clone()। এটা করবেন না। Object.clone()কিছু বড় সমস্যা রয়েছে এবং এর ব্যবহার বেশিরভাগ ক্ষেত্রে নিরুৎসাহিত করা হয়। সম্পূর্ণ উত্তরের জন্য দয়া করে জোশুয়া ব্লচের " কার্যকর জাভা " থেকে আইটেম 11 দেখুন । আমি বিশ্বাস করি আপনি নিরাপদে ব্যবহার করতে পারবেনObject.clone() প্রাথমিকভাবে অ্যারেগুলিতে , তবে এগুলি ছাড়া ক্লোনটি সঠিকভাবে ব্যবহার এবং ওভাররাইড করা সম্পর্কে আপনার বিচার করা দরকার।

সিরিয়ালাইজেশনের উপর নির্ভর করে এমন স্কিমগুলি (এক্সএমএল বা অন্যথায়) ক্লডজি।

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


58

আপনি ফাইল তৈরি না করে সিরিয়ালাইজেশন সহ একটি গভীর অনুলিপি তৈরি করতে পারেন।

আপনার অনুলিপিটির গভীর অনুলিপি করতে ইচ্ছুক আপনার প্রয়োজন implement serializable। যদি ক্লাসটি চূড়ান্ত না হয় বা পরিবর্তন করা যায় না, ক্লাসটি প্রসারিত করুন এবং সিরিয়ালাইজযোগ্য প্রয়োগ করুন।

আপনার শ্রেণিকে বাইটের স্ট্রিমে রূপান্তর করুন:

ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(object);
oos.flush();
oos.close();
bos.close();
byte[] byteData = bos.toByteArray();

বাইটের স্ট্রিম থেকে আপনার শ্রেণি পুনরুদ্ধার করুন:

ByteArrayInputStream bais = new ByteArrayInputStream(byteData);
(Object) object = (Object) new ObjectInputStream(bais).readObject();

4
যদি ক্লাস চূড়ান্ত হয় তবে আপনি কীভাবে এটি প্রসারিত করবেন?
কুমার মনীশ

1
@ কুমারমনিশ ক্লাস মাইকন্টেইনার সিরিয়ালাইজেবল - মাইফাইনাল ক্লাস উদাহরণটি প্রয়োগ করে; ...}
মাত্তিও টি।

আমি এটি একটি দুর্দান্ত উত্তর খুঁজে। ক্লোন একটি জগাখিচুড়ি
ব্ল্যাকবার্ড014

@MatteoT। instanceএই ক্ষেত্রে নন-সিরিয়ালাইজযোগ্য শ্রেণীর সম্পত্তি কীভাবে সিরিয়ালাইজড, অ-সিরিয়ালাইজযোগ্য হবে ?
ফরিদ

\\ আপনি আমার সময় বাঁচিয়েছেন .. অনেক ধন্যবাদ ^ _ ^
মুহাম্মদ এল-বান্না

40

আপনি org.apache.commons.lang3.SerializationUtils.clone(T)অ্যাপাচি কমন্স ল্যাং-এ ব্যবহার করে সিরিয়ালাইজেশন-ভিত্তিক গভীর ক্লোন করতে পারেন , তবে সতর্ক থাকুন — পারফরম্যান্সটি অত্যন্ত অসাধারণ।

সাধারণভাবে, অবজেক্ট গ্রাফের ক্লোনিংয়ের প্রয়োজনীয়তার জন্য প্রতিটি শ্রেণীর জন্য নিজের ক্লোন পদ্ধতি লিখতে ভাল অনুশীলন।


org.apache.commons.lang.SerializationUtils
পিনো

25

গভীর অনুলিপি কার্যকর করার একটি উপায় হ'ল প্রতিটি সম্পর্কিত শ্রেণিতে অনুলিপি নির্মাণকারী যুক্ত করা। একটি অনুলিপি নির্মাণকারী তার একক যুক্তি হিসাবে 'এটি' এর উদাহরণ গ্রহণ করে এবং এটি থেকে সমস্ত মান অনুলিপি করে। বেশ কিছু কাজ, তবে বেশ সোজা এবং নিরাপদ।

সম্পাদনা: নোট করুন যে ক্ষেত্রগুলি পড়তে আপনার অ্যাকসেসর পদ্ধতি ব্যবহার করার দরকার নেই। আপনি সরাসরি সমস্ত ক্ষেত্র অ্যাক্সেস করতে পারেন কারণ উত্স উদাহরণটি সর্বদা অনুলিপি হিসাবে অনুলিপি তৈরির সাথে থাকে। স্পষ্টতই তবে তা উপেক্ষা করা যেতে পারে।

উদাহরণ:

public class Order {

    private long number;

    public Order() {
    }

    /**
     * Copy constructor
     */
    public Order(Order source) {
        number = source.number;
    }
}


public class Customer {

    private String name;
    private List<Order> orders = new ArrayList<Order>();

    public Customer() {
    }

    /**
     * Copy constructor
     */
    public Customer(Customer source) {
        name = source.name;
        for (Order sourceOrder : source.orders) {
            orders.add(new Order(sourceOrder));
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

সম্পাদনা: নোট করুন যে অনুলিপি নির্মাণকারী ব্যবহার করার সময় আপনার অনুলিপি করা অবজেক্টটির রানটাইম ধরণের বিষয়টি জানতে হবে। উপরোক্ত পদ্ধতির সাহায্যে আপনি সহজেই একটি মিশ্র তালিকার অনুলিপি করতে পারবেন না (আপনি কিছু প্রতিবিম্ব কোড দিয়ে এটি করতে সক্ষম হতে পারেন)।


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

আপনার অভিভাবক শ্রেণি কেন এটির সাবক্লাসটি উল্লেখ করে? আপনি কি একটি উদাহরণ দিতে পারেন?
অ্যাড্রায়ান কোস্টার

1
পাবলিক ক্লাস গাড়িটি যানবাহন প্রসারিত করে এবং তারপরে গাড়িটিকে গাড়ি হিসাবে উল্লেখ করে। অরিজিনালিস্ট = নতুন অ্যারেলিস্ট <ওয়েলিক্যাল>; copyList = নতুন অ্যারেলিস্ট <ওয়েভিকাল>; originalList.add (নতুন গাড়ি ()); জন্য (যানবাহন যানবাহন: যানবাহনের তালিকা) L copyList.add (নতুন যানবাহন (যান)); }
শুয়োরের মাংস 'এন' বানি

@ অ্যাডরিয়ানকোস্টার: মূল তালিকায় যদি একটি থাকে তবে Toyotaআপনার কোডটি Carগন্তব্য তালিকায় রাখবে। যথাযথ ক্লোনিংয়ের জন্য সাধারণত শ্রেণীর ভার্চুয়াল ফ্যাক্টরি পদ্ধতি সরবরাহ করা প্রয়োজন যার চুক্তিতে বলা হয়েছে যে এটি তার নিজস্ব শ্রেণীর একটি নতুন বস্তু ফিরিয়ে দেবে; অনুলিপি কন্ট্রাক্টর নিজেই protectedএটি নিশ্চিত হওয়া উচিত যে এটি কেবলমাত্র এমন অবজেক্ট তৈরি করতে ব্যবহার করা হবে যাঁর সুনির্দিষ্ট প্রবন্ধটি অনুলিপি করা হচ্ছে)
সুপারক্যাট

সুতরাং আমি যদি আপনার পরামর্শটি সঠিকভাবে বুঝতে পারি তবে কারখানার পদ্ধতিটি প্রাইভেট কপি কনস্ট্রাক্টরকে কল করবে? একটি সাবক্লাসের অনুলিপি নির্মাণকারী কীভাবে নিশ্চিত করবে যে সুপারক্লাস ক্ষেত্রগুলি আরম্ভ করা হয়েছে? আপনি কি একটি উদাহরণ দিতে পারেন?
অ্যাড্রায়ান কোস্টার

20

আপনি এমন একটি লাইব্রেরি ব্যবহার করতে পারেন যাতে একটি সাধারণ এপিআই থাকে এবং প্রতিবিম্বের সাথে তুলনামূলকভাবে দ্রুত ক্লোনিং সম্পাদন করে (সিরিয়ালাইজেশন পদ্ধতির চেয়ে দ্রুত হওয়া উচিত)।

Cloner cloner = new Cloner();

MyClass clone = cloner.deepClone(o);
// clone is a deep-clone of o

19

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

My_Object object2= org.apache.commons.lang.SerializationUtils.clone(object1);

1
এটি কেবলমাত্র সিরিয়ালাইজেবল প্রয়োগ করে এমন বস্তুর পক্ষে কাজ করে এবং এর মধ্যে সমস্ত ক্ষেত্রের ক্ষেত্রে যদিও সিরিয়ালযোগ্যযোগ্য প্রয়োগ করে।

11

এক্সস্ট্রিম এই জাতীয় দৃষ্টান্তগুলিতে সত্যই কার্যকর। ক্লোনিং করার জন্য এখানে একটি সাধারণ কোড

private static final XStream XSTREAM = new XStream();
...

Object newObject = XSTREAM.fromXML(XSTREAM.toXML(obj));

1
নাও, আপনাকে xML-ing অবজেক্টের ওভারহেডের দরকার নেই।
এজেলেভ

@ ইজলেভ আপনি কি বুঝতে পেরেছেন যে আপনি '08 থেকে কোনও মন্তব্যে জবাব দিচ্ছেন? আমি আর জাভা ব্যবহার করি না এবং এখন সম্ভবত আরও ভাল সরঞ্জাম রয়েছে। তবে সেই সময়, ভিন্ন বিন্যাসে সিরিয়াল করা এবং তারপরে সিরিয়ালাইজিং করা ভাল হ্যাকের মতো মনে হয়েছিল - এটি অবশ্যই অদক্ষ।
শঙ্করা


10

জন্য স্প্রিং ফ্রেমওয়ার্ক ব্যবহারকারীদের। ক্লাস ব্যবহার org.springframework.util.SerializationUtils:

@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T object) {
     return (T) SerializationUtils.deserialize(SerializationUtils.serialize(object));
}

9

জটিল অবজেক্টের জন্য এবং যখন পারফরম্যান্স তাত্পর্যপূর্ণ না হয় আমি জসনের মতো একটি জেসন লাইব্রেরি ব্যবহার করি সাথে বস্তুটিকে সিরিয়ালাইজ করতে , তারপরে নতুন অবজেক্টটি পাওয়ার জন্য পাঠ্যকে করা।

প্রতিচ্ছবি ভিত্তিক জিএসসন বেশিরভাগ ক্ষেত্রে কাজ করবে, transientক্ষেত্রগুলি অনুলিপি করা হবে না এবং কারণের সাথে বিজ্ঞপ্তি রেফারেন্স সহ বস্তুগুলি StackOverflowError

public static <T> T copy(T anObject, Class<T> classInfo) {
    Gson gson = new GsonBuilder().create();
    String text = gson.toJson(anObject);
    T newObject = gson.fromJson(text, classInfo);
    return newObject;
}
public static void main(String[] args) {
    String originalObject = "hello";
    String copiedObject = copy(originalObject, String.class);
}

3
আপনার নিজের এবং আমাদের স্বার্থে দয়া করে জাভা নামকরণের কনভেনশন মেনে চলেন।
প্যাট্রিক বার্গনার

8

এক্সস্ট্রিম ( http://x-stream.github.io/ ) ব্যবহার করুন । এমনকি আপনি টীকাগুলির মাধ্যমে কোন বৈশিষ্ট্য উপেক্ষা করতে পারবেন বা এক্সস্ট্রিম শ্রেণিতে সম্পত্তিটির নাম স্পষ্ট করে উল্লেখ করতে পারবেন তা আপনি নিয়ন্ত্রণ করতে পারেন। তদুপরি আপনার ক্লোনযোগ্য ইন্টারফেস প্রয়োগ করার দরকার নেই।


7

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


2
আপনি কি "উপযুক্ত ডিজাইনের অনুশীলন" বর্ণনা করতে পারেন?
fklappan

6
import com.thoughtworks.xstream.XStream;

public class deepCopy {
    private static  XStream xstream = new XStream();

    //serialize with Xstream them deserialize ...
    public static Object deepCopy(Object obj){
        return xstream.fromXML(xstream.toXML(obj));
    }
}



2

1)

public static Object deepClone(Object object) {
   try {
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     ObjectOutputStream oos = new ObjectOutputStream(baos);
     oos.writeObject(object);
     ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
     ObjectInputStream ois = new ObjectInputStream(bais);
     return ois.readObject();
   }
   catch (Exception e) {
     e.printStackTrace();
     return null;
   }
 }

2)

    // (1) create a MyPerson object named Al
    MyAddress address = new MyAddress("Vishrantwadi ", "Pune", "India");
    MyPerson al = new MyPerson("Al", "Arun", address);

    // (2) make a deep clone of Al
    MyPerson neighbor = (MyPerson)deepClone(al);

এখানে আপনার মাইপারসন এবং মাইএড্রেস ক্লাসকে অবশ্যই সিরিলেজযোগ্য ইন্টারফেস প্রয়োগ করতে হবে


2

জ্যাকসন ব্যবহার করে অবজেক্টটি সিরিয়ালাইজ এবং ডিজাইরিয়াল করা হচ্ছে। এই বাস্তবায়নের জন্য সিরিয়ালাইজেবল শ্রেণি প্রয়োগের জন্য বস্তুর প্রয়োজন হয় না।

  <T> T clone(T object, Class<T> clazzType) throws IOException {

    final ObjectMapper objMapper = new ObjectMapper();
    String jsonStr= objMapper.writeValueAsString(object);

    return objMapper.readValue(jsonStr, clazzType);

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