9

Как скопировать объект в Java?

6

Проблема, с которой я столкнулся, связана с копированием объектов в Java. Рассмотрим следующий код:

DummyBean dum = new DummyBean();
dum.setDummy("foo");
System.out.println(dum.getDummy()); // выводит 'foo'

DummyBean dumtwo = dum;
System.out.println(dumtwo.getDummy()); // выводит 'foo'

dum.setDummy("bar");
System.out.println(dumtwo.getDummy()); // выводит 'bar', хотя должно выводить 'foo'

Я создал объект dum и установил его значение на "foo". Затем я присвоил dum объекту dumtwo. Интересно, что при изменении значения в dum на "bar", dumtwo также отображает это новое значение, вместо того чтобы сохранить "foo".

Я подозреваю, что когда я выполняю dumtwo = dum, Java копирует только ссылку на объект, а не сам объект. Могу ли я создать полноценную копию объекта dum и присвоить ее dumtwo, чтобы изменения в dum не влияли на dumtwo? Как это правильно реализовать?

5 ответ(ов)

1

В пакете import org.apache.commons.lang.SerializationUtils; есть метод:

SerializationUtils.clone(Object);

Этот метод используется для клонирования объектов. Например, вы можете использовать его следующим образом:

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

Этот код создает глубокую копию объекта this.object и сохраняет её в this.myObjectCloned. Это особенно полезно, когда вам нужно создать отдельную копию объекта, чтобы избежать нежелательных изменений исходного объекта. Однако стоит отметить, что для успешного клонирования объект должен реализовывать интерфейс Serializable.

1

Чтобы получить независимую копию объекта, можно использовать метод clone, как показано в следующем примере кода:

public class Deletable implements Cloneable {

    private String str;

    public Deletable() {
    }

    public void setStr(String str) {
        this.str = str;
    }

    public void display() {
        System.out.println("Строка: " + str);
    }

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

Когда вам нужно создать другой объект, просто выполните клонирование. Например:

Deletable del = new Deletable();
Deletable delTemp = (Deletable) del.clone(); // эта строка вернет вам независимый
                                             // объект, изменения, внесенные в этот объект,
                                             // не отобразятся на другом объекте

Таким образом, вы сможете безопасно изменять delTemp, не влияя на оригинальный объект del. Не забудьте обработать возможное исключение CloneNotSupportedException, поскольку метод clone может его вызывать.

0

Проблема отсутствия ответов по использованию 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(childObj));
                }
            }
        }
        return clone;
    } catch (Exception e) {
        return null;
    }
}

Этот метод обрабатывает вложенные объекты и предотвращает бесконечные циклы, когда объект ссылается на самого себя. Обратите внимание, что подход с использованием рефлексии может иметь свои недостатки, такие как снижение производительности и возможные проблемы с безопасностью, поэтому следует использовать его с осторожностью.

0

Если вы используете библиотеку JSON от Google для сериализации объектов и создания их новых экземпляров, будьте внимательны к некоторым ограничениям, связанным с глубоким копированием:

  • Не допускаются рекурсивные ссылки.
  • Не будут скопированы массивы с различными типами.
  • Массивы и списки должны иметь указанный тип, иначе не удастся найти класс для создания экземпляра.
  • Строки могут потребовать обрамления в класс, который вы сами объявите.

Также я использую этот класс для сохранения пользовательских настроек, окон и прочего, что необходимо восстановить в процессе выполнения программы. Это очень удобно и эффективно.

Вот пример кода:

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

С помощью этого класса вы сможете легко сериализовать и десериализовать объекты, а также осуществить глубокое копирование с учетом указанных ограничений.

0

Для выполнения глубокого клонирования в Java вам нужно реализовать интерфейс 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();
      // TODO: скопируйте изменяемые состояния здесь, чтобы клон не мог изменить внутренние данные оригинала
      return cloned;
   }
}

Таким образом, вы можете вызвать клонирование следующим образом:

DummyBean dumtwo = (DummyBean) dum.clone();

Важно помнить, что если ваш класс содержит изменяемые объекты (например, коллекции или пользовательские объекты), вам нужно будет явно создать их копии в методе clone(), чтобы избежать нежелательных изменений в оригинале при изменении клона.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь