2013-04-03 3 views
6

мне нужно оборудовать свой класс с полиморфной вегетативно (глубокая копия), то есть мне нужно что-то вроде этого, чтобы работать:Является ли метод clone() Java единственным способом достижения полиморфного клонирования?

SuperType original = new SubType(); 
SuperType copy = original.clone(); 

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

Способ clone() и интерфейс Cloneable - единственный способ достичь этого? Фабричные методы и конструкторы копирования не могут использоваться, так как фактический класс известен только во время выполнения, правильно? Существуют ли какие-либо другие предлагаемые методы, кроме методов сериализации-десериализации, и Java deep-cloning library, который ИМХО даже хуже черной магии, чем метод clone()?

Спасибо, Петр

+0

Вы не можете создать конструктор, чтобы объект, который вы хотите клонировать, можно передать? – Justin

+0

@gangqinlaohu Конечно, я могу, но тогда мне нужно будет вызвать 'новый SubType (оригинал)', который я не могу, так как не знаю во время написания кода, если оригинал на самом деле принадлежит классу 'SubType' или' SubType2' , или 'SubSubType'. – Posa

ответ

4

На самом деле метод clone() объекта не позволяет вам выполнять какие-либо полиморфные вызовы, потому что это protected. Реализация Cloneable бесполезна либо потому, что не содержит метода clone().

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

abstract class SuperType { 
    public SuperType(SuperType t) { 
    } 

    public abstract SuperType deepCopy(); 
} 

class SomeType extends SuperType { 

    SomeType(SomeType t) { 
     //copy constructor 
    } 

    @Override 
    public SomeType deepCopy() {       
     return new SomeType(this); 
    } 
} 

... 

SuperType original = new SubType(); 
SuperType copy = original.deepCopy(); //the deepCopy is called on children classes 

Смотрите также:

Joshua Block's opinion on cloning vs. copy constructor

+0

ОК, это сработает. Но в каком смысле это отличается от использования 'clone()'? Разве это не просто метод 'deepCopy()' другого имени? Невозможно сделать то же самое в 'deepCopy()' в 'clone()'? – Posa

+0

@Posa Cloning - это «встроенный» способ создания экземпляров объекта без использования конструктора копирования. Он попытался облегчить жизнь программистам, но ИМО это не так. Да, если вы проявляете большую осторожность при переопределении 'clone()' (Javasua Block's Effectiva Java имеет целую главу об этом), вы должны получить те же результаты. – dcernahoschi

1

Вы можете просто добавить метод копирования в Supertype и реализовать его во всех подтипов

class SuperType { 

    public SuperType copy() { 
       ... 
    } 
} 
0

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

+0

Дело не в том, что мне не нравится «Clonable». Я не понимаю пафос dont-use-clone (вероятно, я не совсем понимаю, что выпущено, связанное с «клоном», несмотря на то, что я прочитал книгу Дж. Блоха). Почему вы должны разработать свой собственный интерфейс в основном с той же целью, что и «Clonable»? Или цель моего интерфейса будет отличаться от цели «Clonable»? – Posa

+0

Ну, ваш вопрос: «Является ли метод clone() и Cloneable единственным способом достижения этого?». Если метод clone() подходит для вас, используйте его. Однако использование пользовательского интерфейса позволяет вам воспользоваться преимуществами дженериков. – WilQu

2

Для того, чтобы ваш код работать, этот код либо внутри SuperType класса или подкласса, или ваш SuperType типа должны иметь clone() публичный метод. Общедоступный метод clone() не существует автоматически, и вы должны его реализовать. Вы могли бы назвать это чем-то еще в этом отношении, например. copy().

Ваш вопрос тогда заключается в том, как реализовать этот метод clone() (или как он его называет), чтобы он выполнял полиморфное клонирование.

Способ, который был разработан разработчиками Java, заключается в вызове super.clone(), предполагая, что все классы в иерархии наследования аналогичным образом реализованы для выполнения полиморфного клонирования clone(). Это в конечном итоге доходит до защищенного метода Object.clone(), который делает магию полиморфного клонирования. Обратите внимание, что для Object.clone(), чтобы исключить исключение, ваш класс должен реализовать интерфейс Cloneable.

Однако есть и другие возможные способы. Например, если предположить, что все подклассы имеют конструктор по умолчанию, вы можете сделать что-то вроде this.getClass().newInstance(). Это создаст объект правого класса, но поля не будут скопированы. Ваш метод clone должен будет скопировать все поля, а подклассы должны переопределить ваш метод clone для копирования своих полей и т. Д. Обратите внимание, что в этом случае не имеет значения, реализуется ли интерфейс Cloneable.

Другой способ - предположить, что класс является Serializable, сериализовать и unserialize this. Это должно создать полиморфный клон, который имеет все сериализуемые поля, перенесенные.

Смежные вопросы