Вопрос

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

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

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

Решение

Первое, о чем вы должны знать о Cloneable это - не используйте его.

Очень сложно реализовать клонирование с Cloneable Правильно, и усилия не стоит того.

Вместо этого используют некоторые другие варианты, такие как Apache-Commons SerializationUtils (глубокий клон) или BeanUtils (неглубокий клон) или просто используйте копию-конструктор.

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

Другие советы

Кломируемый сам, к сожалению, просто маркер-интерфейс, то есть не определяет метод клона ().

То, что есть, изменяет поведение метода защищенного объекта .CLONE (), который выбросит клоненоцупопортироватьException для классов, которые не реализуют кломируемым, и выполняют неглубокую копию члена для классов.

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

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

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

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

Большинство разработчиков не используют кломируемые по этим причинам и просто внедряют конструктор копирования.

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

  1. Глонирование вызывает внелингвистический способ построить объекты - без конструкторов.
  2. Клонирование требует от вас как-то относиться к ClonenotsupportedException - или надоедать код клиента для лечения его.
  3. Преимущества небольшие - вам просто не нужно вручную писать конструктор копирования.

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

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

Предположим, у меня есть классы 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, вы не получите правильную копию. И что если а абстракция? Теперь некоторые люди предложили это:

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 клона проблематично. Но это легко преодолеть этот путь:

В классе A:

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):
}

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

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

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

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

Каковы недостатки кломируемых?

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

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

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

Отпустить originalObject закрывает Connection объект, так что сейчас cloneObject не будет работать, потому что connection Объект был разделен между ними, и он был активирован originalObject.

Подобная проблема может возникнуть, если вы хотите сказать, вы хотите клонировать объект, который имеет ioStream в качестве свойства.

Как происходит рекурсивное клонирование, если объект является композитным объектом?

Кложина выполняет мелкую копию. Значение состоит в том, что данные оригинального объекта объекта и клона указывают на одинаковую ссылку / память. Наоборот в случае глубокой копии, данные из памяти исходного объекта копируются в память объекта клона.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top