После большого количества прочтения о многих связанных здесь опциях и возможных решениях этой проблемы, я полагаю, все опции суммированы довольно хорошо по ссылке Ian P ( все остальные варианты являются их вариантами), и наилучшее решение предоставляется ссылкой Pedro77 в комментариях к вопросу.
Так что я просто скопирую соответствующие части этих двух ссылок здесь. Таким образом, мы можем иметь:
Лучшее, что можно сделать для клонирования объектов в диез!
Прежде всего, это все наши варианты:
Статья Fast Deep Copy по деревьям выражений также имеет сравнение производительности клонирования по деревьям сериализации, отражения и выражения.
Почему я выбираю ICloneable (т.е. вручную)
Г-н Венкат Субраманиам (избыточная ссылка здесь) подробно объясняет, почему .
Вся его статья обводится вокруг примера, который пытается быть применимым для большинства случаев, используя 3 объекта: Человек , Мозг и Город . Мы хотим клонировать человека, у которого будет свой мозг, но тот же город. Вы можете изобразить все проблемы, которые могут принести другие методы, описанные выше, или прочитать статью.
Это моя слегка измененная версия его заключения:
Копирование объекта путем указания New
с последующим именем класса часто приводит к тому, что код не является расширяемым. Использование клона, применение шаблона прототипа, является лучшим способом для достижения этой цели. Однако использование клона, как это предусмотрено в C # (и Java), также может быть довольно проблематичным. Лучше предоставить защищенный (непубличный) конструктор копирования и вызвать его из метода clone. Это дает нам возможность делегировать задачу создания объекта экземпляру самого класса, обеспечивая таким образом расширяемость, а также безопасное создание объектов с помощью конструктора защищенной копии.
Надеюсь, эта реализация прояснит ситуацию:
public class Person : ICloneable
{
private final Brain brain; // brain is final since I do not want
// any transplant on it once created!
private int age;
public Person(Brain aBrain, int theAge)
{
brain = aBrain;
age = theAge;
}
protected Person(Person another)
{
Brain refBrain = null;
try
{
refBrain = (Brain) another.brain.clone();
// You can set the brain in the constructor
}
catch(CloneNotSupportedException e) {}
brain = refBrain;
age = another.age;
}
public String toString()
{
return "This is person with " + brain;
// Not meant to sound rude as it reads!
}
public Object clone()
{
return new Person(this);
}
…
}
Теперь рассмотрим класс, производный от Person.
public class SkilledPerson extends Person
{
private String theSkills;
public SkilledPerson(Brain aBrain, int theAge, String skills)
{
super(aBrain, theAge);
theSkills = skills;
}
protected SkilledPerson(SkilledPerson another)
{
super(another);
theSkills = another.theSkills;
}
public Object clone()
{
return new SkilledPerson(this);
}
public String toString()
{
return "SkilledPerson: " + super.toString();
}
}
Вы можете попробовать запустить следующий код:
public class User
{
public static void play(Person p)
{
Person another = (Person) p.clone();
System.out.println(p);
System.out.println(another);
}
public static void main(String[] args)
{
Person sam = new Person(new Brain(), 1);
play(sam);
SkilledPerson bob = new SkilledPerson(new SmarterBrain(), 1, "Writer");
play(bob);
}
}
Результат будет:
This is person with Brain@1fcc69
This is person with Brain@253498
SkilledPerson: This is person with SmarterBrain@1fef6f
SkilledPerson: This is person with SmarterBrain@209f4e
Заметьте, что если мы будем вести подсчет количества объектов, то клон, реализованный здесь, будет вести правильный подсчет количества объектов.