Скопировать объект в Java
У меня есть объект, который мне нужно скопировать на Java. Мне нужно создать копию и выполнить некоторые тесты на ней, не меняя оригинальный объект.
Я предположил, что мне нужно использовать метод clone(), но это защищено. Проведя некоторые исследования в сети, я вижу, что это может быть преодолено с помощью общедоступного метода в моем классе. Но я не могу найти объяснение, как это сделать. Как это можно сделать?
Кроме того, это лучший способ добиться того, что мне нужно?
Ответы
Ответ 1
Другой вариант с помощью Copy Constructor (из Практики Java):
public final class Galaxy {
public Galaxy (double aMass, String aName) {
fMass = aMass;
fName = aName;
}
/**
* Copy constructor.
*/
public Galaxy(Galaxy aGalaxy) {
this(aGalaxy.getMass(), aGalaxy.getName());
//no defensive copies are created here, since
//there are no mutable object fields (String is immutable)
}
/**
* Alternative style for a copy constructor, using a static newInstance
* method.
*/
public static Galaxy newInstance(Galaxy aGalaxy) {
return new Galaxy(aGalaxy.getMass(), aGalaxy.getName());
}
public double getMass() {
return fMass;
}
/**
* This is the only method which changes the state of a Galaxy
* object. If this method were removed, then a copy constructor
* would not be provided either, since immutable objects do not
* need a copy constructor.
*/
public void setMass( double aMass ){
fMass = aMass;
}
public String getName() {
return fName;
}
// PRIVATE /////
private double fMass;
private final String fName;
/**
* Test harness.
*/
public static void main (String... aArguments){
Galaxy m101 = new Galaxy(15.0, "M101");
Galaxy m101CopyOne = new Galaxy(m101);
m101CopyOne.setMass(25.0);
System.out.println("M101 mass: " + m101.getMass());
System.out.println("M101Copy mass: " + m101CopyOne.getMass());
Galaxy m101CopyTwo = Galaxy.newInstance(m101);
m101CopyTwo.setMass(35.0);
System.out.println("M101 mass: " + m101.getMass());
System.out.println("M101CopyTwo mass: " + m101CopyTwo.getMass());
}
}
Ответ 2
Существует два популярных подхода. Один из них заключается в том, чтобы предоставить метод clone
, как вы упомянули, например.
public class C implements Cloneable {
@Override public C clone() {
try {
final C result = (C) super.clone();
// copy fields that need to be copied here!
return result;
} catch (final CloneNotSupportedException ex) {
throw new AssertionError();
}
}
Обратите внимание на "поля копирования... здесь!" часть. Первоначальный result
является только мелкой копией, а это означает, что если есть ссылка на объект, то как исходный, так и result
будут иметь один и тот же объект. Например, если C
содержит private int[] data
, вы, вероятно, захотите его скопировать.
...
final C result = (C) super.clone();
result.data = data.clone();
return result;
...
Обратите внимание, что вам не нужно копировать примитивные поля, поскольку их содержимое уже скопировано или неизменяемые объекты, поскольку они не могут измениться.
Второй подход заключается в предоставлении конструктора копирования.
public class C {
public C(final C c) {
// initialize this with c
}
}
Или копия factory.
public class C {
public static C newInstance(final C c) {
return new C(c);
}
private C(final C c) {
// initialize this with c
}
}
Оба подхода имеют свои соответствующие свойства. clone
приятно, потому что его метод, поэтому вам не нужно знать точный тип. В конце концов, вы всегда должны получить "идеальную" копию. Конструктор копирования хорош, потому что у вызывающего есть возможность решить, как видно из сборников Java.
final List c = ...
// Got c from somewhere else, could be anything.
// Maybe too slow for what we're trying to do?
final List myC = new ArrayList(c);
// myC is an ArrayList, with known properties
Я рекомендую выбрать любой подход, в зависимости от того, что вам подходит.
Я бы использовал другие подходы, такие как рефлексивное копирование или непосредственное сериализация/десериализация, только в модульных тестах. Для меня они менее уместны для производственного кода, главным образом из-за проблем с производительностью.
Ответ 3
Некоторые параметры:
- Вы можете реализовать
Cloneable
для своего объекта и применить метод clone()
как открытый. См. Полное объяснение здесь: http://www.cafeaulait.org/course/week4/46.html
Тем не менее, это создает мелкую копию и может быть не то, что вы хотите.
- Вы можете сериализовать и десериализовать свой объект. Вам нужно будет реализовать интерфейс
Serializable
для объекта и всех его полей.
- Вы можете использовать
XStream
для выполнения сериализации через XML - здесь вам нечего будет реализовывать.
Ответ 4
Для тестового кода Сериализация - это самый безопасный ответ, особенно если объект уже сериализуется. Попробуйте Apache Commons SerializationUtils для реализации.
Ответ 5
Существует несколько способов копирования объекта в java (неглубокий или глубокий).
Этот ответ поможет вам.
Ответ 6
Вы можете использовать класс org.apache.commons.lang3.SerializationUtils для клонирования объектов,
- Класс должен реализовывать интерфейс Serializable.
- ClassName copyobject = SerializationUtils.clone(classobjectTocopy)
SerializationUtils.clone также поддерживается в приложении Google App Engine
Ответ 7
Джошуа Блох несколько интересных вещей, которые можно сказать о клонировании. В зависимости от размера/конструкции объекта я добавляю конструктор копирования к объекту или сериализую/десериализую с помощью одного из упомянутых выше решений.