Яка конкретна причина clone()
визначається як захищена java.lang.Object
?
Яка конкретна причина clone()
визначається як захищена java.lang.Object
?
Відповіді:
Те, що клон захищений, є надзвичайно сумнівним - як і той факт, що clone
метод не оголошується в Cloneable
інтерфейсі.
Це робить метод досить марним для отримання копій даних, оскільки ви не можете сказати :
if(a instanceof Cloneable) {
copy = ((Cloneable) a).clone();
}
Я думаю, що дизайн в Cloneable
даний час багато в чому розглядається як помилка (цитування нижче). Я, як правило, хотів би мати можливість реалізувати інтерфейс, Cloneable
але не обов'язково робити інтерфейсCloneable
(подібний до використання Serializable
). Це неможливо зробити без роздумів:
ISomething i = ...
if (i instanceof Cloneable) {
//DAMN! I Need to know about ISomethingImpl! Unless...
copy = (ISomething) i.getClass().getMethod("clone").invoke(i);
}
Цитування з ефективної Java Джоша Блоха :
"Інтерфейс, що клонується, був призначений як інтерфейс для змішування об'єктів, які рекламують, що вони дозволяють клонувати. На жаль, це не відповідає цій цілі ... Це вкрай нетипове використання інтерфейсів, а не імітація. ... Для того, щоб реалізація інтерфейсу мала будь-який вплив на клас, він і всі його суперкласи повинні підкорятися досить складному, невиконаному та багато в чому недокументованому протоколу "
Serializable
- вирішувати, чи потрібно реалізовувати, залежить від реалізації Serializable
. Я поширював це на Cloneable
це - це не те, на що повинен поширюватися інтерфейс, - але реалізація інтерфейсу може бути вільною Cloneable
. Проблема полягає в тому, що якщо у вас є параметр типу інтерфейсу, ви запитаєте його, чи він може бути клонований; але тоді ви насправді не можете його клонувати!
Інтерфейс Clonable - це лише маркер, який каже, що клас може підтримувати клон. Метод захищений, тому що ви не повинні викликати його на об'єкті, ви можете (і повинні) його замінити як загальнодоступний.
Від сонця:
У класі Object метод clone () оголошується захищеним. Якщо все, що ви робите, це реалізація Cloneable, лише підкласи та члени одного пакету зможуть викликати clone () на об'єкті. Щоб увімкнути будь-який клас у будь-якому пакеті доступ до методу clone (), вам доведеться його перекрити і оголосити загальнодоступним, як це робиться нижче. (Коли ви заміняєте метод, ви можете зробити його менш приватним, але не більш приватним. Тут метод захищеного клонування () в Object переосмислюється як публічний метод.)
Set
clone
захищено, оскільки це щось, що повинно бути відмінено, щоб воно було специфічним для поточного класу. Хоча можна було б створити публічний clone
метод, який би взагалі клонував будь-який об’єкт, це було б не так добре, як метод, написаний спеціально для класу, який цього потребує.
Метод Clone не може бути безпосередньо використаний на жодному об'єкті, тому його передбачає переозброєння підкласом.
Звичайно, це може бути загальнодоступним і просто кинути відповідний виняток, коли клонування неможливо, але я думаю, що це було б оманливим.
Спосіб реалізації клона прямо зараз змушує задуматися про те, чому ви хочете використовувати клон, і як ви хочете клонувати ваш об’єкт.
Він захищений, оскільки реалізація за замовчуванням виконує неглибоку копіювальну за всіма полями (включаючи приватну), обходячи конструктор . Це не те, що об’єкт може бути призначений для обробки в першу чергу (наприклад, він може відслідковувати створені екземпляри об'єктів у спільному списку чи щось подібне).
З тієї ж причини реалізація за замовчуванням clone()
буде кидатися, якщо об'єкт, на який він викликається, не реалізує Cloneable
. Це потенційно небезпечна операція з далекосяжними наслідками, і тому автор класу повинен чітко відмовитися.
З явадока клонів.
* By convention, classes that implement this interface (cloneable) should override
* <tt>Object.clone</tt> (which is protected) with a public method.
* See {@link java.lang.Object#clone()} for details on overriding this
* method.
* Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
* Therefore, it is not possible to clone an object merely by virtue of the
* fact that it implements this interface. Even if the clone method is invoked
* reflectively, there is no guarantee that it will succeed.
Таким чином, ви можете викликати клона на кожному об'єкті, але це дасть вам більшу частину часу не потрібні результати або виняток. Але рекомендується лише в тому випадку, якщо ви реалізуєте cloneable.
IMHO це так просто, як це:
#clone
не слід викликати об'єкти, що не підлягають клонуванню, тому вони не оприлюднюються#clone
повинен викликатися підкласами ob, Object
які реалізують Cloneable, щоб отримати дрібну копію потрібного класуЯке правильне поле для методів, які слід називати підкласами, а не іншими класами?
Це protected
.
Заняття, що реалізують Cloneable
курс, зробить цей метод загальнодоступним, тому його можна буде викликати з інших класів.
Метод Clone () має внутрішню перевірку "екземпляра Cloneable чи ні". Саме так, як вважає команда Java, обмежується неналежне використання методу clone () method.clone () захищено, тобто доступ до нього здійснюється лише підкласами. Оскільки об'єкт є батьківським класом усіх підкласів, то метод Clone () може бути використаний усіма класами infact, якщо у нас немає вище перевірки "екземпляра Cloneable". З цієї причини, можливо, команда Java подумала обмежити неправильне використання clone (), встановивши перевірку методом clone () "це екземпляр Cloneable".
Отже, які б класи не реалізували cloneable, можуть використовувати метод clone () класу Object.
Оскільки він захищений, він доступний лише тим підкласам, які реалізують інтерфейс, що підлягає клонуванню. Якщо ми хочемо оприлюднити його, цей метод повинен бути замінений підкласом із їх власною реалізацією.
Так, та сама проблема, з якою я і зустрічався. Але я це вирішую, реалізуючи цей код
public class Side implements Cloneable {
public Side clone() {
Side side = null;
try {
side = (Side) super.clone();
} catch (CloneNotSupportedException e) {
System.err.println(e);
}
return side;
}
}
Так само, як раніше хтось сказав.
Ну, а також розробники сонця є лише людьми, і вони дійсно зробили величезну помилку в застосуванні методу клонування як захищеного, та ж помилка, що вони застосували непрацюючий метод клонування в ArrayList! Отже, загалом існує набагато глибше непорозуміння навіть досвідчених програмістів Java щодо методу клонування.
Однак нещодавно я знайшов швидке і просте рішення скопіювати будь-який об’єкт з усім його вмістом, незалежно від того, як він побудований і що він містить, дивіться мою відповідь тут: Помилка використання Object.clone ()
Знову ж таки, рамка Java JDK демонструє геніальне мислення:
Інтерфейс, що піддається клонуванню, не містить "загальнодоступного клона T ();" метод, оскільки він більше схожий на атрибут (наприклад, Serializable), що дозволяє його екземпляру клонувати.
У цьому дизайні немає нічого поганого, оскільки:
Object.clone () не буде робити те, що ви хочете, з вашим призначеним для користувача класом.
Якщо у вас Myclass реалізує Cloneable => ви перезаписуєте clone () з "public clone MyClass ()"
Якщо у вас MyInterface розширює Cloneable та деякі MyClasses, що реалізують MyInterface: просто визначте "загальний клон MyInterface ();" в інтерфейсі та кожному методі, що використовує MyInterface, об'єкти зможуть їх клонувати, незалежно від класу MyClass.