it-swarm-id.com

Bagaimana Anda membuat salinan objek di Jawa?

Dalam Java agak sulit untuk mengimplementasikan fungsi penyalinan objek dalam. Langkah apa yang Anda ambil untuk memastikan objek asli dan bagian hasil kloning tidak memiliki referensi?

277
Andrei Savu

Cara yang aman adalah membuat serialisasi objek, lalu deserialize. Ini memastikan semuanya adalah referensi baru.

Inilah artikel tentang cara melakukan ini secara efisien.

Peringatan: Mungkin bagi kelas untuk mengabaikan serialisasi sehingga instance baru tidak dibuat, mis. untuk lajang. Juga ini tentu saja tidak berfungsi jika kelas Anda tidak Serializable.

161
Jason Cohen

Beberapa orang telah menyebutkan penggunaan atau penggantian Object.clone(). Jangan lakukan itu. Object.clone() memiliki beberapa masalah besar, dan penggunaannya tidak disarankan dalam banyak kasus. Silakan lihat Butir 11, dari " Java Efektif " oleh Joshua Bloch untuk jawaban yang lengkap. Saya percaya Anda dapat menggunakan Object.clone() dengan aman pada array tipe primitif, tetapi selain itu Anda harus bijaksana dalam menggunakan dan mengganti klon secara benar.

Skema yang mengandalkan serialisasi (XML atau yang lain) adalah kludgy.

Tidak ada jawaban yang mudah di sini. Jika Anda ingin menyalin objek secara mendalam, Anda harus melintasi grafik objek dan menyalin setiap objek anak secara eksplisit melalui copy constructor objek atau metode pabrik statis yang pada gilirannya akan menyalin objek anak secara mendalam. Immutables (mis. Strings) tidak perlu disalin. Sebagai tambahan, Anda harus mendukung ketidakberdayaan karena alasan ini.

67
Julien Chastang

Anda dapat membuat salinan yang dalam dengan serialisasi tanpa membuat file.

Objek Anda yang ingin Anda salin dalam perlu _ implement serializable. Jika kelas tidak final atau tidak dapat dimodifikasi, perluas kelas dan implementasikan serializable.

Konversi kelas Anda ke aliran byte:

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

Pulihkan kelas Anda dari aliran byte:

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

Anda dapat melakukan klon mendalam berbasis serialisasi menggunakan org.Apache.commons.lang3.SerializationUtils.clone(T) di Apache Commons Lang, tapi hati-hati — kinerjanya buruk.

Secara umum, ini adalah praktik terbaik untuk menulis metode klon Anda sendiri untuk setiap kelas objek dalam grafik objek yang membutuhkan kloning.

37
user8690

Salah satu cara untuk mengimplementasikan deep copy adalah dengan menambahkan copy constructor ke setiap kelas terkait. Pembuat salinan mengambil contoh 'ini' sebagai argumen tunggal dan menyalin semua nilai darinya. Cukup banyak pekerjaan, tetapi cukup mudah dan aman.

EDIT: perhatikan bahwa Anda tidak perlu menggunakan metode accessor untuk membaca bidang. Anda dapat mengakses semua bidang secara langsung karena instance sumber selalu dari tipe yang sama dengan instance dengan konstruktor salin. Jelas tetapi mungkin diabaikan.

Contoh:

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;
    }
}

Sunting: Perhatikan bahwa ketika menggunakan copy constructor Anda perlu mengetahui tipe runtime dari objek yang Anda salin. Dengan pendekatan di atas Anda tidak dapat dengan mudah menyalin daftar campuran (Anda mungkin dapat melakukannya dengan beberapa kode refleksi).

23
Adriaan Koster

Apache commons menawarkan cara cepat untuk mengkloning objek secara mendalam.

My_Object object2= org.Apache.commons.lang.SerializationUtils.clone(object1);
19
TheByeByeMan

Anda dapat menggunakan perpustakaan yang memiliki API sederhana, dan melakukan kloning yang relatif cepat dengan refleksi (harus lebih cepat daripada metode serialisasi).

Cloner cloner = new Cloner();

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

XStream sangat berguna dalam hal ini. Berikut ini adalah kode sederhana untuk melakukan kloning

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

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

Salah satu pendekatan yang sangat mudah dan sederhana adalah dengan menggunakan Jackson JSON untuk membuat cerita bersambung kompleks Java Objek ke JSON dan membacanya kembali.

http://wiki.fasterxml.com/JacksonInFiveMinutes

9
Ravi Chinoy

Untuk Kerangka Kerja Musim Semi pengguna. Menggunakan kelas org.springframework.util.SerializationUtils:

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

Gunakan XStream ( http://x-stream.github.io/ ). Anda bahkan dapat mengontrol properti mana yang bisa Anda abaikan melalui anotasi atau secara eksplisit menentukan nama properti ke kelas XStream. Selain itu Anda tidak perlu mengimplementasikan antarmuka yang dapat dikloning.

8
Adi

Untuk objek yang rumit dan ketika kinerjanya tidak signifikan saya menggunakan pustaka json, seperti gson untuk membuat serialisasi objek menjadi teks json, lalu menghapus teks untuk mendapatkan objek baru.

gson yang berdasarkan refleksi akan bekerja dalam banyak kasus, kecuali bahwa bidang transient tidak akan disalin dan objek dengan referensi melingkar dengan penyebab 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);
}
7
tiboo

Penyalinan yang dalam hanya dapat dilakukan dengan persetujuan masing-masing kelas. Jika Anda memiliki kendali atas hierarki kelas maka Anda dapat mengimplementasikan antarmuka yang dapat dikloning dan mengimplementasikan metode Klon. Kalau tidak, melakukan penyalinan dalam tidak mungkin dilakukan dengan aman karena objek mungkin juga berbagi sumber daya non-data (mis. Koneksi basis data). Secara umum, namun penyalinan dalam dianggap praktik buruk di lingkungan Java dan harus dihindari melalui praktik desain yang sesuai.

7
Orion Adrian
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));
    }
}
6
user946968

Saya menggunakan Dozer untuk mengkloning objek Java dan itu hebat, Kryo library adalah alternatif hebat lainnya.

4
supernova

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);

Di sini, kelas MyPerson dan MyAddress Anda harus mengimplementasikan antarmuka yang dapat diseret

2
Arun

BeanUtils melakukan pekerjaan yang sangat baik dalam mengkloning kacang.

BeanUtils.cloneBean(obj);
1
Alfergon