Jak skopiować obiekt w Javie?
Rozważ poniższy kod:
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'
Chcę więc skopiować dum
do dumtwo
I zmienić dum
bez wpływu na dumtwo
. Ale powyższy kod tego nie robi. Kiedy zmieniam coś w dum
, ta sama zmiana dzieje się również w dumtwo
.
Wydaje mi się, że Kiedy mówię dumtwo = dum
, Java kopiuje tylko odniesienia . Czy jest jakiś sposób na utworzenie nowej kopii dum
i przypisanie jej do dumtwo
?
21 answers
Utwórz konstruktor kopii:
class DummyBean {
private String dummy;
public DummyBean(DummyBean another) {
this.dummy = another.dummy; // you can access
}
}
Każdy obiekt ma również metodę klonowania, która może być użyta do skopiowania obiektu, ale jej nie używaj. Zbyt łatwo jest utworzyć klasę i wykonać niewłaściwą metodę klonowania. Jeśli masz zamiar to zrobić, przeczytaj przynajmniej co Joshua Bloch ma do powiedzenia na ten temat w skuteczna Java.
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
2009-05-15 14:47:40
Basic: kopiowanie obiektów w Javie.
Przyjmijmy obiekt - obj1
, który zawiera dwa obiekty, containedObj1 i containedObj2.
Płytkie kopiowanie:
shallow copying tworzy nową instance
tej samej klasy i kopiuje wszystkie pola do nowej instancji i zwraca je. klasa obiektu zapewnia metodę clone
i zapewnia wsparcie dla płytki kopiuję.
Głębokie kopiowanie:
Głęboka Kopia występuje, gdy obiekt jest kopiowany wraz z obiektami, do których się odnosi . Poniższy obrazek pokazuje obj1
po wykonaniu na nim głębokiej kopii. nie tylko obj1
zostały skopiowane , ale także obiekty w nim zawarte. Możemy użyć Java Object Serialization
do zrobienia głębokiej kopii. Niestety, takie podejście ma również pewne problemy (szczegółowe przykłady ).
Możliwe problemy:clone
jest trudne do prawidłowego wdrożenia.
Lepiej używać defensywnego kopiowania, konstruktory kopiujące(jako odpowiedź @egaga) lub statyczne metody fabryczne .
- jeśli masz obiekt, o którym wiesz, że ma publiczną metodę
clone()
, ale nie znasz typu obiektu w czasie kompilacji, to masz problem. Java posiada interfejs o nazwieCloneable
. W praktyce powinniśmy wdrożyć to interfejs, jeśli chcemy stworzyć obiektCloneable
.Object.clone
jest chronione , więc musimy nadpisać, aby był dostępny.
- inny problem pojawia się, gdy próbujemy głębokiego kopiowania złożonego obiektu. Załóżmy, że metoda
clone()
wszystkich zmiennych obiektu członkowskiego również wykonuje głęboką kopię, jest to zbyt ryzykowne z założenia. Musisz kontrolować kod we wszystkich klasach.
Na przykład org.Apacz.commons.lang.SerializationUtils będzie miał metodę głębokiego klonowania przy użyciu serializacji (źródło ). Jeśli musimy sklonować Bean, istnieje kilka metod użytkowych w org.Apacz.commons.beanutils (źródło ).
-
cloneBean
Sklonuje bean na podstawie dostępnych właściwości getters i setters, nawet jeśli sama klasa bean nie implementuje Cloneable. -
copyProperties
skopiuje wartości właściwości z oryginału do miejsce przeznaczenia dla wszystkich przypadków, w których nazwy nieruchomości są takie same.
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-05-02 04:50:10
W OPAKOWANIU import org.apache.commons.lang.SerializationUtils;
znajduje się metoda:
SerializationUtils.clone(Object);
Przykład:
this.myObjectCloned = SerializationUtils.clone(this.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
2013-05-02 20:14:54
Po prostu postępuj jak poniżej:
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();
}
}
I gdziekolwiek chcesz uzyskać inny obiekt, wykonaj proste klonowanie. e. g:
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
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
2011-10-20 15:46:05
Dlaczego nie ma odpowiedzi na używanie API Reflection?
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;
}
}
To naprawdę proste.
EDIT: Include child object via recursion
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;
}
}
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-08-29 09:49:50
Używam Biblioteki JSON Google, aby serializować go, a następnie utworzyć nową instancję serializowanego obiektu. Robi głębokie kopiowanie z kilkoma ograniczeniami:
-
Nie może być żadnych odwołań rekurencyjnych
-
Nie będzie kopiować tablic różnych typów
-
Tablice i listy powinny być wpisywane lub nie znajdzie klasy do utworzenia instancji
-
Może być konieczne zamknięcie łańcuchów w klasie, którą deklarujesz
Używam również tej klasy do Zapisz preferencje użytkownika, okna i inne rzeczy, które mają być przeładowane w czasie wykonywania. Jest bardzo łatwy w użyciu i skuteczny.
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;
}
}
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-07-09 20:14:24
Tak, tylko odwołujesz się do obiektu. Możesz sklonować obiekt, jeśli implementuje on Cloneable
.
Sprawdź ten artykuł na wiki o kopiowaniu obiektów.
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-28 09:40:26
Tak. Musisz głęboko skopiować swój obiekt.
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
2009-05-15 14:35:02
Dodaj Cloneable
i poniższy kod do swojej klasy
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
Użyj tego clonedObject = (YourClass) yourClassObject.clone();
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-07-31 15:00:04
Oto przyzwoite Wyjaśnienie clone()
jeśli będziesz tego potrzebował...
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-28 09:41:02
To też działa. Model zakładający
class UserAccount{
public int id;
public String name;
}
Pierwszy dodaj
compile 'com.google.code.gson:gson:2.8.1'
do Twojej aplikacji>gradle & sync. Then
Gson gson = new Gson();
updateUser = gson.fromJson(gson.toJson(mUser),UserAccount.class);
Można wykluczyć użycie pola za pomocą słowa kluczowego transient
po modyfikatorze dostępu.
Uwaga: to jest zła praktyka. Nie zaleca się również używania Cloneable
lub JavaSerialization
jest powolny i zepsuty. Napisz Konstruktor kopiujący dla najlepszej wydajności ref .
Coś jak
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);
}
}
Statystyki testu 90000 iteracji:
Linia UserAccount clone = gson.fromJson(gson.toJson(aO), UserAccount.class);
zajmuje 808ms
Linia UserAccount clone = new UserAccount(aO);
zajmuje mniej niż 1ms
Wniosek: użyj gson, jeśli twój szef jest szalony i wolisz szybkość. Użyj drugiego konstruktora kopiującego, jeśli wolisz jakość.
Możesz również użyć kodu konstruktora kopiującego wtyczki generatora W Android Studio.
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-09-23 06:24:15
Aby to zrobić, musisz sklonować obiekt w jakiś sposób. Chociaż Java ma mechanizm klonowania, nie używaj go, jeśli nie musisz. Utwórz metodę kopiowania, która wykonuje Kopiowanie za Ciebie, a następnie wykonaj:
dumtwo = dum.copy();
Tutaj jest kilka porad na temat różnych technik wykonania kopii.
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-05-23 12:26:42
Głębokie klonowanie jest twoją odpowiedzią, która wymaga implementacji interfejsu Cloneable
i nadpisania metody 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,
// however, in case of non primitive types
// cloned.setNonPrimitiveType(cloned.getNonPrimitiveType().clone());
return cloned;
}
}
Nazwiesz to tak
DummyBean dumtwo = dum.clone();
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-30 19:51:59
Użyj narzędzia do głębokiego klonowania:
SomeObjectType copy = new Cloner().deepClone(someObject);
To głęboko skopiuje dowolny obiekt java, sprawdź to na https://github.com/kostaskougios/cloning
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-12-13 14:43:22
INNE niż jawne kopiowanie, inne podejście polega na uczynieniu obiektu niezmiennym (brak set
lub innych metod mutatora). W ten sposób pytanie nigdy nie powstaje. Niezmienność staje się trudniejsza w przypadku większych obiektów, ale ta druga strona jest taka, że popycha cię w kierunku podziału na spójne małe obiekty i kompozyty.
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
2009-05-15 14:43:35
class DB {
private String dummy;
public DB(DB one) {
this.dummy = one.dummy;
}
}
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-03-02 13:35:20
Podaj obiekt, który chcesz skopiować i pobierz obiekt, który chcesz skopiować,
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;
}
Teraz przeanalizuj obiekt, który jest najbardziej obiektowy.
Happy Coding
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-12-07 13:25:22
Możesz spróbować zaimplementować Cloneable
i użyć metody clone()
; jednak jeśli używasz metody klonowania, powinieneś - standardowo-zawsze nadpisać Object
'S public Object clone()
metoda.
Możesz kopiować automatycznie za pomocą XStream, z http://x-stream.github.io/:
XStream jest prostą biblioteką do serializacji obiektów do XML i z powrotem jeszcze raz.
Dodaj go do swojego projektu (jeśli używasz Mavena)
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.3.1</version>
</dependency>
Then
DummyBean dum = new DummyBean();
dum.setDummy("foo");
DummyBean dumCopy = (DummyBean) XSTREAM.fromXML(XSTREAM.toXML(dum));
Z tym masz kopię bez konieczności implementacji jakiegokolwiek interfejsu 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
2015-08-11 18:35:31
Jeśli możesz dodać adnotację do pliku źródłowego, można użyć procesora adnotacji lub generatora kodu, takiego jak Ten.
import net.zerobuilder.BeanBuilder
@BeanBuilder
public class DummyBean {
// bean stuff
}
Zostanie wygenerowana klasa DummyBeanBuilders
, która ma statyczną metodę dummyBeanUpdater
do tworzenia płytkich kopii, tak samo jak zrobiłbyś to ręcznie.
DummyBean bean = new DummyBean();
// Call some setters ...
// Now make a copy
DummyBean copy = DummyBeanBuilders.dummyBeanUpdater(bean).done();
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-02-14 05:45:49
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();
}
}
}
I w kodzie:
MyClass myClass = new MyClass();
// do some work with this object
MyClass clonedMyClass = myClass.clone();
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-08-10 13:26:48