О Java cloneable

Я искал некоторые учебники, объясняющие о Java Cloneable, но не получил хороших ссылок, и переполнение стека становится более очевидным выбором в любом случае.

Я хотел бы знать следующее:

  1. Cloneable означает, что мы можем иметь клона или копию объектов, реализация Cloneable интерфейс. Каковы преимущества и недостатки этого?
  2. как происходит рекурсивное клонирование, если объект является смешанный объект?

6 ответов


первое, что вы должны знать о!--0--> is-Не используйте его.

очень трудно реализовать клонирование с помощью Cloneable правильно, и усилия того не стоят.

вместо этого используйте некоторые другие параметры, такие как apache-commons SerializationUtils (глубокий-клон) или BeanUtils (shallow-clone) или просто используйте конструктор копирования.

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


Cloneable сам по себе, к сожалению, просто интерфейс маркера, то есть: он не определяет метод clone ().

Что делает, это изменение поведения защищаемого объекта.метод clone (), который будет вызывать исключение CloneNotSupportedException для классов, которые не реализуют Cloneable, и выполнять мелкую копию по элементам для классов, которые это делают.

даже если это поведение, которое вы ищете, вам все равно нужно будет реализовать свой собственный метод clone (), чтобы сделать ее публичной.

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

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

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

большинство разработчиков не используют Cloneable по этим причинам, и просто реализуйте конструктор копирования.

для получения дополнительной информации и потенциальных ловушек Cloneable, я настоятельно рекомендую книгу эффективная Java Джошуа Блоха


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

Итак, используйте Cloneable разумно. Это не дает вам достаточных преимуществ по сравнению с усилиями, которые вам нужно приложить, чтобы сделать все право.


клонирование является базовой парадигмой программирования. Тот факт, что Java, возможно, плохо реализовал его во многих отношениях, вовсе не уменьшает необходимость клонирования. И легко реализовать клонирование, которое будет работать, как вы хотите, чтобы он работал, мелкий, глубокий, смешанный, что угодно. Вы даже можете использовать имя clone для функции и не реализовывать Cloneable, если хотите.

предположим, что у меня есть классы A, B и C, где B и C являются производными от A. Если у меня есть список объектов типа A, подобных это:

ArrayList<A> list1;

теперь этот список может содержать объекты типа A, B или C. Вы не знаете, какой тип объектов. Таким образом, вы не можете скопировать список следующим образом:

ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
    list2.add(new A(a));
}

если объект на самом деле имеет тип B или C, вы не получите правильную копию. И что, если A абстрактно? Теперь, некоторые люди предложили это:

ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
    if(a instanceof A) {
        list2.add(new A(a));
    } else if(a instanceof B) {
        list2.add(new B(a));
    } else if(a instanceof C) {
        list2.add(new C(a));
    }
}

это очень, очень плохая идея. Что делать, если вы добавите новый производный тип? Что делать, если B или C находятся в другом пакете, и у вас нет доступа к они в этом классе?

что вы хотели бы сделать это:

ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
    list2.add(a.clone());
}

многие люди указали, почему основная реализация Java clone проблематична. Но, это легко преодолеть таким образом:

в:

public A clone() {
    return new A(this);
}

в классе B:

@Override
public B clone() {
    return new B(this);
}

в классе C:

@Override
public C clone() {
    return new C(this):
}

Я не реализую Cloneable, просто используя то же имя функции. Если тебе это не нравится, назови что-нибудь другое.


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

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

Божо прав, клон может быть трудно получить права. Конструктор/фабрика копирования будет обслуживать большинство потребностей.


каковы недостатки Cloneable?

клонирование очень опасно, если объект, который вы копируете, имеет состав.В этом случае вам нужно подумать о возможном побочном эффекте ниже, потому что clone создает мелкую копию:

пусть у вас есть один объект для обработки манипуляций, связанных с db. Скажем, этот объект имеет Connection объект как одно из свойств.

поэтому, когда кто-то создает клон originalObject, создаваемый объект, пусть скажи,cloneObject. Здесь originalObject и cloneObject удерживайте одну и ту же ссылку для