Как скопировать объект в Java?
рассмотрим код ниже:
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
to dumtwo
, и dum
не затрагивая dumtwo
. Но приведенный выше код этого не делает. Когда я что-то меняю в dum
, то же самое изменение происходит в dumtwo
также.
наверное, когда я говорю dumtwo = dum
, Java копирует справки. Итак, есть ли способ создать новую копию dum
и назначить dumtwo
?
21 ответов
создать конструктор копии:
class DummyBean {
private String dummy;
public DummyBean(DummyBean another) {
this.dummy = another.dummy; // you can access
}
}
каждый объект также имеет метод клонирования, который можно использовать для копирования объекта, но не использовать его. Слишком легко создать класс и сделать неправильный метод клонирования. Если вы собираетесь это сделать, прочитайте, по крайней мере, что Джошуа блох должен сказать об этом в Эффективная Java.
Basic: копирование объектов на Java.
предположим объект -obj1
, который содержит два объекта, containedObj1 и containedObj2.
неглубокое копирование:
мелкое копирование создает новый instance
того же класса и копирует все поля в новый экземпляр и возвращает его. объект класса предоставляет clone
метод и обеспечивает поддержку неглубокого копирования.
код:
Глубокая копия возникает, когда объект копируется вместе с объектами, к которым он относится. Ниже изображение показывает obj1
после того, как на нем была выполнена глубокая копия. не только obj1
скопировать, но объекты, содержащиеся в нем, также были скопированы. Мы можем использовать Java Object Serialization
чтобы сделать глубокую копию. К сожалению, этот подход имеет некоторые проблемы тоже(подробные примеры).
Возможные Проблемы:clone
сложно реализовать правильно.
Лучше использовать защитное копирование, конструкторы копирования(как @egaga ответить) или статические методы фабрики.
- если у вас есть объект, который вы знаете, имеет общедоступный
clone()
метод, но вы не знаете типом объекта при компиляции время, тогда у вас проблема. Java имеет интерфейс под названиемCloneable
. На практике, мы должны реализовать этот интерфейс, если мы хотим сделать объектCloneable
.Object.clone
и защищенный, так что мы должны переопределить он с публичным методом, чтобы он был доступен.
- другая проблема возникает, когда мы пытаемся код of a сложный объект. Предположим, что
clone()
метод всех переменных объекта-члена также делает глубокая копия, это слишком рискованное предположение. Вы должны контролировать код во всех классах.
-
cloneBean
будет клонировать боб на основе доступные геттеры и сеттеры свойств, даже если сам класс bean не реализует Cloneable. -
copyProperties
будет копировать значения свойств из исходного компонента в целевой компонент для всех случаев, когда имена свойств одинаковы.
в пакете import org.apache.commons.lang.SerializationUtils;
есть такой метод:
SerializationUtils.clone(Object);
пример:
this.myObjectCloned = SerializationUtils.clone(this.object);
просто следуйте, как показано ниже:
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
почему нет ответа на использование 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;
}
}
это очень просто.
EDIT: включить дочерний объект через рекурсию
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;
}
}
Я использую библиотеку JSON Google для сериализации, а затем создаю новый экземпляр сериализованного объекта. Он делает глубокую копию с несколькими ограничениями:
не может быть рекурсивной ссылки
он не будет копировать массивы разрозненных типов
массивы и списки должны быть введены, или он не найдет класс для создания экземпляра
возможно, Вам потребуется инкапсулировать строки в объявленном классе себя!--2-->
Я также использую этот класс для сохранения пользовательских настроек, windows и whatnot для перезагрузки во время выполнения. Он очень прост в использовании и эффективен.
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;
}
}
Да, вы просто делаете ссылку на объект. Вы можете клонировать объект, если он реализует Cloneable
.
проверьте эту статью wiki о копировании объектов.
добавить Cloneable
и ниже кода для вашего класса
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
использовать clonedObject = (YourClass) yourClassObject.clone();
это тоже работает. Предполагая модель
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
он медленный и нарушен. Написать конструктор копирования для лучшей производительности ref.
что-то как
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.
для этого вам нужно каким-то образом клонировать объект. Хотя Java имеет механизм клонирования, не используйте его, если вам это не нужно. Создайте метод копирования, который выполняет работу копирования для вас, а затем выполните:
dumtwo = dum.copy();
здесь это еще несколько советов по различным методам выполнения копии.
глубокое клонирование-ваш ответ, который требует реализации 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,
// however, in case of non primitive types
// cloned.setNonPrimitiveType(cloned.getNonPrimitiveType().clone());
return cloned;
}
}
вы назовете это так
DummyBean dumtwo = dum.clone();
используйте утилиту глубокого клонирования:
SomeObjectType copy = new Cloner().deepClone(someObject);
Это будет глубоко копировать любой объект java, проверьте его вhttps://github.com/kostaskougios/cloning
кроме явного копирования, другой подход - сделать объект неизменяемым (нет set
или другие методы мутатора). Таким образом вопрос никогда не возникает. Неизменность становится более трудной с большими объектами, но другая сторона этого заключается в том, что она толкает вас в направлении расщепления на когерентные маленькие объекты и композиты.
передайте объект, который вы хотите скопировать, и получите объект, который вы хотите,
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 на объект desigered.
Удачи В Кодировании
вы можете попробовать реализовать Cloneable
и с помощью clone()
метод; однако, если вы используете метод клонирования, вы должны - по стандарту - всегда переопределять Object
' s public Object clone()
метод.
вы можете глубоко копировать автоматически с 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));
С этим у вас есть копия без необходимости реализации какого-либо интерфейса клонирования.
если вы можете добавить аннотацию в исходный файл, обработчик аннотаций или генератор кода, например этот можно использовать.
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();
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();