ฉันจะคัดลอกวัตถุใน Java ได้อย่างไร


794

พิจารณารหัสด้านล่าง:

DummyBean dum = new DummyBean();
dum.setDummy("foo");
System.out.println(dum.getDummy()); // prints 'foo'

DummyBean dumtwo = dum;
System.out.println(dumtwo.getDummy()); // prints 'foo'

dum.setDummy("bar");
System.out.println(dumtwo.getDummy()); // prints 'bar' but it should print 'foo'

ดังนั้นผมต้องการที่จะคัดลอกdumไปdumtwoและการเปลี่ยนแปลงได้โดยไม่ต้องมีผลกระทบต่อdum dumtwoแต่รหัสข้างต้นไม่ได้ทำอย่างนั้น เมื่อฉันเปลี่ยนบางสิ่งในสิ่งdumเดียวกันก็เกิดขึ้นdumtwoเช่นกัน

ผมคิดว่าเมื่อฉันพูดdumtwo = dum, Java สำเนาการอ้างอิงเท่านั้น ดังนั้นมีวิธีการสร้างสำเนาใหม่dumและกำหนดให้dumtwo?

คำตอบ:


611

สร้างตัวสร้างสำเนา:

class DummyBean {
  private String dummy;

  public DummyBean(DummyBean another) {
    this.dummy = another.dummy; // you can access  
  }
}

วัตถุทุกชิ้นมีวิธีการโคลนซึ่งสามารถใช้เพื่อคัดลอกวัตถุ แต่ไม่ได้ใช้ มันง่ายเกินไปในการสร้างคลาสและทำวิธีการโคลนที่ไม่เหมาะสม หากคุณกำลังจะไปทำอย่างนั้นอ่านอย่างน้อยสิ่งที่โจชัวโบลชได้กล่าวเกี่ยวกับเรื่องนี้ในที่มีประสิทธิภาพ Java


45
แต่แล้วเขาจะต้องเปลี่ยนรหัสของเขาเป็น DummyBean two = new DummyBean (หนึ่ง); ขวา?
คริส K

12
วิธีนี้ทำได้อย่างมีประสิทธิภาพเช่นเดียวกับสำเนาลึกหรือไม่?
Matthew Piziak

124
@ MatewewPiziak สำหรับฉัน - นี่จะไม่ใช่การโคลนนิ่งที่ลึกเนื่องจากวัตถุที่ซ้อนกันใด ๆ จะยังคงอ้างอิงอินสแตนซ์ต้นฉบับไม่ซ้ำกันเว้นแต่วัตถุการอ้างอิง (ชนิดที่ไม่ใช่ค่า) จะให้เทมเพลตคอนสตรัคเตอร์เดียวกันตามข้างบน
SliverNinja - MSFT

17
@ Timmmm: ใช่พวกเขาจะอ้างอิงสตริงเดียวกัน แต่เพราะมันไม่เปลี่ยนรูปก็โอเค กันไปสำหรับดั้งเดิม สำหรับ non-primitives คุณจะทำการคัดลอกการเรียกตัวสร้างซ้ำซ้ำ เช่นถ้า DummyBean อ้างอิง FooBar ดังนั้น FooBar ควรมีโครงสร้าง FooBar (FooBar อีกคน) และ Dummy ควรเรียก this.foobar = FooBar ใหม่ (another.foobar)
egaga

7
@ChristianVielma: ไม่มันไม่ใช่ "johndoe" เช่นเดียวกับ Timmmm กล่าวว่าตัวสตริงนั้นไม่เปลี่ยนรูป ด้วยหนึ่ง setDummy (.. ) คุณตั้งค่าการอ้างอิงในหนึ่งให้ชี้ไปที่ "johndoe" แต่ไม่ใช่หนึ่งในหนึ่ง
keuleJ

404

พื้นฐาน:การคัดลอกวัตถุใน Java

ขอให้เราถือว่าวัตถุobj1ที่ประกอบด้วยวัตถุสองcontainedObj1และcontainedObj2
ป้อนคำอธิบายรูปภาพที่นี่

การคัดลอกตื้น: การคัดลอก
ตื้นสร้างใหม่instanceของคลาสเดียวกันและคัดลอกฟิลด์ทั้งหมดไปยังอินสแตนซ์ใหม่และส่งคืน คลาสอ็อบเจ็กต์จัดเตรียมcloneเมธอดและจัดเตรียมการสนับสนุนสำหรับการทำสำเนาแบบตื้น
ป้อนคำอธิบายรูปภาพที่นี่

คัดลอกลึก:
สำเนาลึกเกิดขึ้นเมื่อวัตถุถูกคัดลอกไปพร้อมกับวัตถุซึ่งหมายถึง ภาพด้านล่างแสดงobj1หลังจากทำสำเนาลึก ไม่เพียง แต่obj1ถูกคัดลอกแต่วัตถุที่อยู่ภายในนั้นถูกคัดลอกเช่นกัน เราสามารถใช้Java Object Serializationเพื่อทำสำเนาลึก น่าเสียดายที่วิธีการนี้มีปัญหาเช่นกัน ( ตัวอย่างโดยละเอียด )
ป้อนคำอธิบายรูปภาพที่นี่

ปัญหาที่
cloneเป็นไปได้:ยุ่งยากในการใช้อย่างถูกต้อง
มันเป็นเรื่องดีที่จะใช้การคัดลอกการป้องกัน , การคัดลอกก่อสร้าง (เป็นตอบ @egaga) หรือวิธีการโรงงานแบบคงที่

  1. หากคุณมีวัตถุที่คุณรู้ว่ามีclone()วิธีสาธารณะแต่คุณไม่ทราบชนิดของวัตถุในเวลารวบรวมแล้วคุณมีปัญหา Java Cloneableมีอินเตอร์เฟซที่เรียกว่า Cloneableในทางปฏิบัติเราควรใช้อินเตอร์เฟซนี้ถ้าเราต้องการที่จะทำให้วัตถุ Object.cloneจะได้รับการคุ้มครองดังนั้นเราจึงต้องแทนที่มันด้วยวิธีการในที่สาธารณะเพื่อให้มันสามารถเข้าถึงได้
  2. อีกปัญหาหนึ่งที่เกิดขึ้นเมื่อเราพยายามคัดลอกลึกของวัตถุที่ซับซ้อน สมมติว่าclone()เมธอดของตัวแปรออบเจกต์สมาชิกทั้งหมดทำการคัดลอกที่ลึกเกินไปซึ่งมีความเสี่ยงต่อการสันนิษฐานเกินไป คุณต้องควบคุมรหัสในทุกชั้น

ตัวอย่างเช่นorg.apache.commons.lang.SerializationUtilsจะมีวิธีการสำหรับการโคลนแบบลึกโดยใช้การทำให้เป็นอนุกรม (ที่มา ) ถ้าเราต้องการโคลน Bean มีวิธีการอรรถประโยชน์สองอย่างในorg.apache.commons.beanutils ( ที่มา )

  • cloneBean จะทำการลอกข้อมูล bean โดยอิงตามคุณสมบัติของ getters และ setters ที่มีอยู่แม้ว่าคลาส bean นั้นจะไม่สามารถใช้ Cloneable ได้
  • copyProperties จะคัดลอกค่าคุณสมบัติจาก Origin bean ไปยังปลายทาง bean สำหรับทุกกรณีที่ชื่อคุณสมบัติเหมือนกัน

1
คุณช่วยอธิบายสิ่งที่มีวัตถุภายในอื่นได้ไหม
Freakyuser

1
@Chandra Sekhar "การคัดลอกตื้นสร้างอินสแตนซ์ใหม่ของคลาสเดียวกันและคัดลอกฟิลด์ทั้งหมดไปที่อินสแตนซ์ใหม่และส่งกลับ" นั่นผิดที่จะพูดถึงฟิลด์ทั้งหมดวัตถุ bcz ไม่ได้คัดลอกเฉพาะการอ้างอิงที่คัดลอกไป วัตถุเดียวกันกับที่วัตถุเก่า (ต้นฉบับ) ชี้ไป
JAVA

4
@sunny - คำอธิบายของ Chandra ถูกต้อง และคำอธิบายของคุณในสิ่งที่เกิดขึ้นคือ; ฉันกำลังบอกว่าคุณมีความเข้าใจที่ไม่ถูกต้องเกี่ยวกับความหมายของ เขตข้อมูลเป็นการอ้างอิงไม่ใช่วัตถุที่ถูกอ้างถึง "การคัดลอกฟิลด์ทั้งหมด" หมายถึง "การคัดลอกข้อมูลอ้างอิงทั้งหมด" มันเป็นการดีที่คุณชี้ให้เห็นว่าสิ่งนี้มีความหมายอย่างไรสำหรับคนอื่น ๆ ที่มีการตีความผิด ๆ เช่นเดียวกับคุณในคำแถลงว่า "การคัดลอกทุกสาขา" :)
ToolmakerSteve

2
... ถ้าเราคิดในแง่ของภาษา OO ระดับต่ำกว่าด้วย "พอยน์เตอร์" ไปยังวัตถุฟิลด์ดังกล่าวจะมีที่อยู่ในหน่วยความจำ (เช่น "0x70FF1234") ซึ่งพบข้อมูลวัตถุ ที่อยู่นั้นคือ "ค่าของฟิลด์" ที่จะถูกคัดลอก (มอบหมาย) คุณถูกต้องว่าผลลัพธ์สุดท้ายคือวัตถุทั้งสองมีเขตข้อมูลที่อ้างถึงวัตถุเดียวกัน
ToolmakerSteve

127

ในแพ็คเกจimport org.apache.commons.lang.SerializationUtils;มีวิธีการ:

SerializationUtils.clone(Object);

ตัวอย่าง:

this.myObjectCloned = SerializationUtils.clone(this.object);

59
ตราบเท่าที่วัตถุดำเนินการSerializable
Androiderson

2
ในกรณีนี้วัตถุที่โคลนไม่มีการอ้างอิงถึงต้นฉบับถ้าวัตถุสุดท้ายคงที่
Dante

8
ห้องสมุดบุคคลที่สามเพียงเพื่อโคลนวัตถุ!
Khan

2
@Khan "ห้องสมุดบุคคลที่สามเพียงเพื่อ" เป็นการสนทนาที่แยกจากกันโดยสิ้นเชิง! : D
Charles Wood

103

เพียงทำตามด้านล่าง:

public class Deletable implements Cloneable{

    private String str;
    public Deletable(){
    }
    public void setStr(String str){
        this.str = str;
    }
    public void display(){
        System.out.println("The String is "+str);
    }
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

และทุกที่ที่คุณต้องการรับวัตถุอื่นทำการโคลนอย่างง่าย เช่น:

Deletable del = new Deletable();
Deletable delTemp = (Deletable ) del.clone(); // this line will return you an independent
                                 // object, the changes made to this object will
                                 // not be reflected to other object

1
คุณทดสอบสิ่งนี้หรือไม่? ฉันสามารถใช้สิ่งนี้กับโครงการของฉันและเป็นสิ่งสำคัญที่จะต้องถูกต้อง
หมอก

2
@isty ฉันได้ทำการทดสอบแล้ว ทำงานได้อย่างสมบูรณ์บนแอปโปรดักชั่นของฉัน
Andrii Kovalchuk

หลังจากการโคลนเมื่อคุณปรับเปลี่ยนวัตถุต้นฉบับมันจะทำการดัดแปลงโคลนเช่นกัน
Sibish

4
นี่เป็นความผิดพลาดที่ไม่ใช่สำเนาที่ถูกขอ
Bluehorn

1
วิธีนี้โคลนตัวชี้ที่ชี้ไปที่วัตถุที่ลอกเลียนแบบได้ แต่คุณสมบัติทั้งหมดภายในวัตถุทั้งสองเหมือนกันดังนั้นจึงมีวัตถุใหม่ที่สร้างขึ้นในหน่วยความจำ แต่ข้อมูลภายในแต่ละวัตถุเป็นข้อมูลเดียวกันจากหน่วยความจำ
Omar HossamEldin

40

ทำไมไม่มีคำตอบสำหรับการใช้ Reflection API

private static Object cloneObject(Object obj){
        try{
            Object clone = obj.getClass().newInstance();
            for (Field field : obj.getClass().getDeclaredFields()) {
                field.setAccessible(true);
                field.set(clone, field.get(obj));
            }
            return clone;
        }catch(Exception e){
            return null;
        }
    }

มันง่ายจริงๆ

แก้ไข: รวมวัตถุลูกผ่านการเรียกซ้ำ

private static Object cloneObject(Object obj){
        try{
            Object clone = obj.getClass().newInstance();
            for (Field field : obj.getClass().getDeclaredFields()) {
                field.setAccessible(true);
                if(field.get(obj) == null || Modifier.isFinal(field.getModifiers())){
                    continue;
                }
                if(field.getType().isPrimitive() || field.getType().equals(String.class)
                        || field.getType().getSuperclass().equals(Number.class)
                        || field.getType().equals(Boolean.class)){
                    field.set(clone, field.get(obj));
                }else{
                    Object childObj = field.get(obj);
                    if(childObj == obj){
                        field.set(clone, clone);
                    }else{
                        field.set(clone, cloneObject(field.get(obj)));
                    }
                }
            }
            return clone;
        }catch(Exception e){
            return null;
        }
    }

สิ่งนี้ดูดีกว่ามาก แต่คุณต้องพิจารณาเฉพาะฟิลด์สุดท้ายเนื่องจาก setAccessible (จริง) อาจล้มเหลวดังนั้นคุณอาจต้องจัดการข้อยกเว้น IllegalAccessException ที่ถูกโยนทิ้งเมื่อเรียกใช้ field.set (clone, field.get (obj)) ต่างหาก
สูงสุด

1
ฉันชอบมันมาก แต่คุณสามารถสร้างใหม่เพื่อใช้ยาสามัญ? ส่วนตัวคง <T> T cloneObject (T obj) {.... }
Adelin

2
ฉันคิดว่ามันเป็นปัญหาเมื่อเรามีการอ้างอิงจากคุณสมบัติไปยังผู้ปกครอง: Class A { B child; } Class B{ A parent; }
nhthai

มันล้มเหลวแม้ในสถานการณ์เช่นนี้จำเป็นต้องได้รับการจัดการฉันจะเล่นกับมันในวันพรุ่งนี้ class car { car car = new car(); }
JánЯabčan

2
นี่เป็นข้อผิดพลาดได้ง่าย ไม่แน่ใจว่ามันจะจัดการกับคอลเลกชันได้อย่างไร
ACV

31

ฉันใช้ไลบรารี JSON ของ Google เพื่อทำให้เป็นอนุกรมจากนั้นสร้างอินสแตนซ์ใหม่ของวัตถุที่ต่อเนื่องกัน มันทำสำเนาลึกโดยมีข้อ จำกัด เล็กน้อย:

  • ไม่สามารถอ้างอิงซ้ำได้

  • มันจะไม่คัดลอกอาร์เรย์ของประเภทที่แตกต่างกัน

  • ควรพิมพ์อาร์เรย์และรายการไม่เช่นนั้นจะไม่พบคลาสที่จะยกตัวอย่าง

  • คุณอาจจำเป็นต้องแค็ปซูลสตริงในชั้นเรียนที่คุณประกาศตัวเอง

ฉันยังใช้คลาสนี้เพื่อบันทึกการตั้งค่าของผู้ใช้ windows และอะไรที่จะโหลดซ้ำในขณะใช้งานจริง มันใช้งานง่ายและมีประสิทธิภาพ

import com.google.gson.*;

public class SerialUtils {

//___________________________________________________________________________________

public static String serializeObject(Object o) {
    Gson gson = new Gson();
    String serializedObject = gson.toJson(o);
    return serializedObject;
}
//___________________________________________________________________________________

public static Object unserializeObject(String s, Object o){
    Gson gson = new Gson();
    Object object = gson.fromJson(s, o.getClass());
    return object;
}
       //___________________________________________________________________________________
public static Object cloneObject(Object o){
    String s = serializeObject(o);
    Object object = unserializeObject(s,o);
    return object;
}
}

มันใช้งานได้ดี แต่ระวังถ้าคุณพยายามโคลนบางอย่างเช่น List <Integer> มันจะเป็นบั๊กกี้ Integers ของฉันกลายเป็นคู่ผสม 100.0 ฉันใช้เวลานานพอสมควรที่จะเข้าใจว่าทำไมพวกเขาถึงเป็นอย่างนั้น การแก้ปัญหาคือการโคลนพวกเขาหนึ่งโดยหนึ่งและเพิ่มในรายการในรอบ
paakjis


14

เพิ่มCloneableและด้านล่างรหัสให้ชั้นเรียนของคุณ

public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

ใช้สิ่งนี้ clonedObject = (YourClass) yourClassObject.clone();



12

มันก็ใช้ได้เช่นกัน สมมติว่าเป็นแบบจำลอง

class UserAccount{
   public int id;
   public String name;
}

เพิ่ม compile 'com.google.code.gson:gson:2.8.1'ในแอพของคุณก่อน> gradle & sync แล้วก็

Gson gson = new Gson();
updateUser = gson.fromJson(gson.toJson(mUser),UserAccount.class);

คุณสามารถยกเว้นการใช้ฟิลด์โดยใช้transientคำหลักหลังจากตัวดัดแปลงการเข้าถึง

หมายเหตุ:นี่เป็นวิธีปฏิบัติที่ไม่ดี ยังไม่แนะนำให้ใช้CloneableหรือJavaSerializationมันช้าและแตก เขียนตัวสร้างสำเนาเพื่อการอ้างอิงที่ดีที่สุดโทษ

สิ่งที่ต้องการ

class UserAccount{
        public int id;
        public String name;
        //empty constructor
        public UserAccount(){}
        //parameterize constructor
        public UserAccount(int id, String name) {
            this.id = id;
            this.name = name;
        }

        //copy constructor
        public UserAccount(UserAccount in){
            this(in.id,in.name);
        }
    }

สถิติทดสอบของการวนซ้ำ 90000:
บรรทัดUserAccount clone = gson.fromJson(gson.toJson(aO), UserAccount.class);ใช้เวลา808ms

เส้นUserAccount clone = new UserAccount(aO);ใช้เวลาน้อยกว่า1 มิลลิวินาที

สรุป:ใช้ gson ถ้าเจ้านายของคุณบ้าและคุณชอบความเร็ว ใช้ตัวสร้างสำเนาที่สองหากคุณต้องการคุณภาพ

คุณยังสามารถใช้ปลั๊กอินตัวสร้างโค้ดตัวสร้างโค้ดใน Android Studio


ทำไมคุณถึงแนะนำถ้ามันเป็นการปฏิบัติที่ไม่ดี?
Parth Mehrotra

ขอบคุณ @ParthMehrotra ตอนนี้ได้รับการปรับปรุง
Qamar


9

ใช้ยูทิลิตี้การโคลนแบบลึก:

SomeObjectType copy = new Cloner().deepClone(someObject);

สิ่งนี้จะคัดลอกออบเจ็กต์ Java ใด ๆ อย่างลึกซึ้งตรวจสอบที่https://github.com/kostaskougios/cloning


1
ไม่ได้ผลสำหรับฉันโดยใช้คลาสที่กำหนดเอง รับข้อยกเว้นต่อไปนี้: java.lang.NoClassDefFoundError: sun.reflect.ReflectionFactory
stefanjunker

9

การโคลนนิ่งลึกคือคำตอบของคุณซึ่งจำเป็นต้องใช้Cloneableอินเทอร์เฟซและเอาชนะclone()วิธีการ

public class DummyBean implements Cloneable {

   private String dummy;

   public void setDummy(String dummy) {
      this.dummy = dummy;
   }

   public String getDummy() {
      return dummy;
   }

   @Override
   public Object clone() throws CloneNotSupportedException {
      DummyBean cloned = (DummyBean)super.clone();
      cloned.setDummy(cloned.getDummy());
      // the above is applicable in case of primitive member types like String 
      // however, in case of non primitive types
      // cloned.setNonPrimitiveType(cloned.getNonPrimitiveType().clone());
      return cloned;
   }
}

คุณจะเรียกมันว่าเป็นแบบนี้ DummyBean dumtwo = dum.clone();


2
dummy, a String, ไม่เปลี่ยนรูปคุณไม่จำเป็นต้องคัดลอก
Steve Kuo

7

ในการทำเช่นนั้นคุณต้องทำการโคลนนิ่งวัตถุในบางวิธี แม้ว่า Java จะมีกลไกการโคลนนิ่ง แต่อย่าใช้หากคุณไม่จำเป็นต้องทำ สร้างวิธีการคัดลอกที่ทำงานให้คุณแล้ว:

dumtwo = dum.copy();

ต่อไปนี้เป็นคำแนะนำเพิ่มเติมเกี่ยวกับเทคนิคต่างๆในการทำสำเนาให้สำเร็จ


6

นอกเหนือจากการคัดลอกอย่างชัดเจนแนวทางอื่นคือการทำให้วัตถุไม่เปลี่ยนรูป (ไม่มีsetหรือวิธีการเปลี่ยนแปลงอื่น ๆ ) ด้วยวิธีนี้คำถามไม่เคยเกิดขึ้น การเปลี่ยนไม่ได้จะกลายเป็นเรื่องยากมากขึ้นกับวัตถุที่มีขนาดใหญ่กว่า แต่อีกด้านหนึ่งของสิ่งนั้นคือมันผลักคุณไปในทิศทางของการแยกออกเป็นวัตถุและคอมโพสิตขนาดเล็กที่ต่อเนื่องกัน


5

ทางเลือกของตัวสร้างวิธีการคัดลอกegaga คุณอาจมี POJO อยู่แล้วดังนั้นเพียงเพิ่มวิธีอื่นcopy()ที่ส่งคืนสำเนาของวัตถุที่เริ่มต้นได้

class DummyBean {
    private String dummyStr;
    private int dummyInt;

    public DummyBean(String dummyStr, int dummyInt) {
        this.dummyStr = dummyStr;
        this.dummyInt = dummyInt;
    }

    public DummyBean copy() {
        return new DummyBean(dummyStr, dummyInt);
    }

    //... Getters & Setters
}

หากคุณมีDummyBeanและต้องการสำเนา:

DummyBean bean1 = new DummyBean("peet", 2);
DummyBean bean2 = bean1.copy(); // <-- Create copy of bean1 

System.out.println("bean1: " + bean1.getDummyStr() + " " + bean1.getDummyInt());
System.out.println("bean2: " + bean2.getDummyStr() + " " + bean2.getDummyInt());

//Change bean1
bean1.setDummyStr("koos");
bean1.setDummyInt(88);

System.out.println("bean1: " + bean1.getDummyStr() + " " + bean1.getDummyInt());
System.out.println("bean2: " + bean2.getDummyStr() + " " + bean2.getDummyInt());

เอาท์พุท:

bean1: peet 2
bean2: peet 2

bean1: koos 88
bean2: peet 2

แต่ทั้งคู่ทำงานได้ดีมันขึ้นอยู่กับคุณ ...



3

คุณสามารถทำสำเนาลึกโดยอัตโนมัติด้วย XStream จากhttp://x-stream.github.io/ :

XStream เป็นห้องสมุดง่าย ๆ ในการทำให้เป็นอันดับวัตถุกับ XML และกลับมาอีกครั้ง

เพิ่มไปยังโครงการของคุณ (ถ้าใช้ maven)

<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.3.1</version>                
</dependency>

แล้วก็

DummyBean dum = new DummyBean();
dum.setDummy("foo");
DummyBean dumCopy = (DummyBean) XSTREAM.fromXML(XSTREAM.toXML(dum));

ด้วยวิธีนี้คุณมีสำเนาโดยไม่จำเป็นต้องใช้ส่วนต่อประสานการโคลนใด ๆ


29
การแปลงเป็น XML จาก / ดูไม่สวยมาก ที่จะนำมันอย่างอ่อนโยน!
Timmmm

ลองดูjava.beans.XMLEncoderJava API มาตรฐานที่ต่อเนื่องกับ XML ด้วยเช่นกัน (แม้ว่าจะไม่ใช่จุดประสงค์ในการทำสำเนาแบบลึก)
Jaime Hablutzel

1
คุณรู้ไหมว่านี่มันหนักแค่ไหน
mahieddine

1
ความคิดเห็นของฉันมีค่าใช้จ่ายสูงมากเนื่องจากคุณจำเป็นต้องเพิ่มห้องสมุดบุคคลที่สามและทำการจัดลำดับวัตถุซึ่งน่าจะมีผลกระทบอย่างมากต่อประสิทธิภาพการทำงาน
NiThDi

2
public class MyClass implements Cloneable {

private boolean myField= false;
// and other fields or objects

public MyClass (){}

@Override
public MyClass clone() throws CloneNotSupportedException {
   try
   {
       MyClass clonedMyClass = (MyClass)super.clone();
       // if you have custom object, then you need create a new one in here
       return clonedMyClass ;
   } catch (CloneNotSupportedException e) {
       e.printStackTrace();
       return new MyClass();
   }

  }
}

และในรหัสของคุณ:

MyClass myClass = new MyClass();
// do some work with this object
MyClass clonedMyClass = myClass.clone();

2
ไม่มีจุดในชุด "throw CloneNotSupportedException" ในการประกาศถ้าคุณลองตรวจจับข้อยกเว้นและจะไม่ส่งออกไป ดังนั้นคุณสามารถลบออกได้
Christian

2

ส่งผ่านวัตถุที่คุณต้องการคัดลอกและรับวัตถุที่คุณต้องการ:

private Object copyObject(Object objSource) {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(objSource);
            oos.flush();
            oos.close();
            bos.close();
            byte[] byteData = bos.toByteArray();
            ByteArrayInputStream bais = new ByteArrayInputStream(byteData);
            try {
                objDest = new ObjectInputStream(bais).readObject();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return objDest;

    }

ตอนนี้แยกวิเคราะห์objDestวัตถุที่ต้องการ

Happy Coding!


1

คุณสามารถลองใช้Cloneableและใช้clone()วิธีการนั้น แต่ถ้าคุณใช้วิธีการโคลนที่คุณควร - มาตรฐาน - แทนที่เสมอObject's public Object clone()วิธี


1

หากคุณสามารถเพิ่มคำอธิบายประกอบลงในไฟล์ต้นฉบับตัวประมวลผลคำอธิบายประกอบหรือตัวสร้างโค้ดเช่นนี้สามารถใช้ได้

import net.zerobuilder.BeanBuilder

@BeanBuilder
public class DummyBean { 
  // bean stuff
}

ชั้นเรียนDummyBeanBuildersจะถูกสร้างขึ้นซึ่งมีวิธีการแบบคงที่dummyBeanUpdaterเพื่อสร้างสำเนาตื้น ๆ เช่นเดียวกับที่คุณจะทำมันด้วยตนเอง

DummyBean bean = new DummyBean();
// Call some setters ...
// Now make a copy
DummyBean copy = DummyBeanBuilders.dummyBeanUpdater(bean).done();

0

ใช้gsonสำหรับทำสำเนาวัตถุ

public static <T>T copyObject(Object object){
    Gson gson = new Gson();
    JsonObject jsonObject = gson.toJsonTree(object).getAsJsonObject();
    return gson.fromJson(jsonObject,(Type) object.getClass());
}

สมมติว่าฉันมีวัตถุpersonดังนั้น

Person copyPerson = copyObject(person);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.