Jak zrobić głęboką kopię obiektu w Javie?
W Javie jest nieco trudno zaimplementować funkcję głębokiego kopiowania obiektów. Jakie kroki należy podjąć, aby upewnić się, że oryginalny obiekt i sklonowany nie mają żadnego odniesienia?
17 answers
Bezpiecznym sposobem jest serializacja obiektu, a następnie deserializacja. Zapewnia to, że wszystko jest zupełnie nowym punktem odniesienia.
Oto Artykuł o tym, jak to zrobić skutecznie.
Zastrzeżenia: możliwe jest, aby klasy nadpisywały serializację tak, że nowe instancje są tworzone , a nie, np. dla singletonów. Również to oczywiście nie działa, jeśli Twoje klasy nie są Serializowalne.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-15 15:42:23
Kilka osób wspomniało o używaniu lub nadpisywaniu Object.clone()
. Nie rób tego. Object.clone()
ma kilka poważnych problemów, a jego stosowanie jest zniechęcające w większości przypadków. Pełna odpowiedź znajduje się w punkcie 11 z "Effective Java" Joshuy Bloch. Wierzę, że można bezpiecznie używać Object.clone()
Na prymitywnych tablicach typu, ale poza tym trzeba rozsądnie używać i nadpisywać klon.
Schematy, które opierają się na serializacji (XML lub w inny sposób), są kludgy.
There is no easy odpowiedz tutaj. Jeśli chcesz głęboko skopiować obiekt, musisz przejść przez wykres obiektu i skopiować każdy obiekt potomny jawnie za pomocą konstruktora kopiującego obiektu lub statycznej metody fabrycznej, która z kolei głęboko kopiuje obiekt potomny. Obiekty niezmienne (np. String
s) nie muszą być kopiowane. Z tego powodu powinieneś faworyzować niezmienność.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-13 07:50:46
Możesz zrobić głęboką kopię z serializacją bez tworzenia plików.
Twój obiekt, który chcesz głęboko skopiować, będzie musiał implement serializable
. Jeśli klasa nie jest ostateczna lub nie może zostać zmodyfikowana, rozszerz klasę i zaimplementuj serializable.
Konwertuj klasę na strumień bajtów:
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(object);
oos.flush();
oos.close();
bos.close();
byte[] byteData = bos.toByteArray();
Przywróć klasę ze strumienia bajtów:
ByteArrayInputStream bais = new ByteArrayInputStream(byteData);
(Object) object = (Object) new ObjectInputStream(bais).readObject();
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-07 13:22:57
Możesz wykonać głęboki klon oparty na serializacji za pomocą org.apache.commons.lang3.SerializationUtils.clone(T)
w Apache Commons Lang, ale uważaj-wydajność jest fatalna.
Ogólnie rzecz biorąc, najlepszą praktyką jest pisanie własnych metod klonowania dla każdej klasy obiektu w grafie obiektów wymagających klonowania.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-09 14:59:52
Jednym ze sposobów implementacji głębokiej kopii jest dodanie konstruktorów kopiujących do każdej powiązanej klasy. Konstruktor kopiujący pobiera instancję 'this' jako swój pojedynczy argument i kopiuje z niego wszystkie wartości. Trochę pracy, ale całkiem proste i bezpieczne.
EDIT: zauważ, że nie musisz używać metod dostępu do odczytu pól. Możesz uzyskać dostęp do wszystkich pól bezpośrednio, ponieważ instancja źródłowa jest zawsze tego samego typu co instancja z konstruktorem kopiującym. Oczywiste, ale może być / align = "left" /
Przykład:
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;
}
}
Edit: zauważ, że podczas używania konstruktorów kopiujących musisz znać typ runtime kopiowanego obiektu. Przy powyższym podejściu nie można łatwo skopiować listy mieszanej (być może uda się to zrobić za pomocą kodu refleksyjnego).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-27 07:50:30
Apache commons oferuje szybki sposób na głębokie sklonowanie obiektu.
My_Object object2= org.apache.commons.lang.SerializationUtils.clone(object1);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-28 14:53:24
Możesz użyć biblioteki , która ma proste API i wykonuje stosunkowo szybkie klonowanie z odbiciem (powinno być szybsze niż metody serializacji).
Cloner cloner = new Cloner();
MyClass clone = cloner.deepClone(o);
// clone is a deep-clone of o
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-13 07:51:08
XStream jest naprawdę przydatny w takich przypadkach. Oto prosty kod do klonowania
private static final XStream XSTREAM = new XStream();
...
Object newObject = XSTREAM.fromXML(XSTREAM.toXML(obj));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-23 08:03:08
Jednym bardzo łatwym i prostym podejściem jest użycie Jacksona JSONA do serializacji złożonego obiektu Javy do JSON i odczytania go z powrotem.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-07 03:51:31
Use XStream ( http://x-stream.github.io/). możesz nawet kontrolować, które właściwości możesz ignorować poprzez adnotacje lub jawne podanie nazwy właściwości do klasy XStream. Co więcej, nie musisz implementować interfejsu klonowalnego.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-02 11:35:00
Głębokie kopiowanie może być wykonane tylko za zgodą każdej klasy. Jeśli masz kontrolę nad hierarchią klas, możesz zaimplementować interfejs klonowalny i zaimplementować metodę klonowania. W przeciwnym razie wykonanie głębokiej kopii jest niemożliwe do zrobienia bezpiecznie, ponieważ obiekt może również współdzielić zasoby inne niż dane (np. połączenia z bazą danych). Ogólnie jednak głębokie kopiowanie jest uważane za złą praktykę w środowisku Java i powinno być unikane poprzez odpowiednie praktyki projektowe.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-15 15:44:32
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));
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-21 00:58:35
Do skomplikowanych obiektów i gdy wydajność nie jest znacząca używam biblioteki json, jak gson aby serializować obiekt do tekstu json, następnie deserializować tekst, aby uzyskać nowy obiekt.
Gson, który bazuje na odbiciu będzie działał w większości przypadków, z tą różnicą, że transient
Pola nie będą kopiowane, a obiekty z kolistym odniesieniem z przyczyną 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);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-19 10:30:33
Użyłem Dozer do klonowania obiektów Javy i jest w tym świetny, Kryo Biblioteka jest kolejną świetną alternatywą.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-17 02:08:59
Dla Spring Framework użytkowników. Klasa org.springframework.util.SerializationUtils
:
@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T object) {
return (T) SerializationUtils.deserialize(SerializationUtils.serialize(object));
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-19 22:15:18
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);
Tutaj twoja klasa MyPerson i myaddress musi zaimplementować interfejs serilazable
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-11 14:51:53
BeanUtils robi naprawdę dobrą robotę Głębokie klonowanie fasoli.
BeanUtils.cloneBean(obj);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-16 10:24:08