Клонирование объектов в Java [3 вопроса]

будет ли при этом вызываться метод клонирования Asub? Или Asub глубоко клонирован правильно? Если нет, есть ли способ правильно глубоко клонировать Asub с помощью такого метода?

abstract class Top extends TopMost {
    protected Object clone() {
        Object obj = super.clone();
        // deep copy and try catch
    }


}

abstract class A extends Top { 
    protected Object clone() {
        Object obj = super.clone();
       // deep copy and try catch
    } 


}

class Asub extends A {
    protected Object clone() {
        Object obj = super.clone();
        // deep copy and try catch
    }

    public void doSomethingNew() {
    }
}

abstract class TopMost {
    public void someMethod() {
        Top a = (Top) super.clone();
        // more code here
    }
}

public class Main {
    public static void main(String... args) {
        Asub class1 = new Asub();
        class1.someMethod();
    }
}

person setzamora    schedule 06.09.2010    source источник


Ответы (3)


Разрешение всех подклассов abstract, реализующих super.clone(), по существу ничего не делает (поскольку все ваши абстрактные классы в вашем примере ничего не делают) и просто вызывает (в конце) метод Object.clone().

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

e.g.

public abstract class TopMost {

    public TopMost(TopMost rhs) {

    }

}

public abstract class Top extends TopMost {

    public Top(Top rhs) {
        super(rhs);

        //whatever you need from rhs that only is visible from top
    }
}

public abstract class A extends Top { 

    public A (A rhs) {
        super(rhs);

        //TODO: do rhs copy
    }
}

public class ASub extends A {

    public ASub(ASub rhs) {
        super(rhs);

        //TODO: copy other stuff here....
    }

    public Object clone() {
        return new ASub(this);
    }
}

PS Сделать TopMost клонируемым

person Buhake Sindi    schedule 06.09.2010
comment
К сожалению, если ASub является подклассом, подкласс clone() может не вызывать super.clone(), так как он возвращает ASub вместо ASubSub. Так что это работает только в том случае, если у вас есть полный контроль над всей иерархией классов навсегда (и тщательно задокументирована несовместимая реализация clone для своих преемников). - person Péter Török; 06.09.2010
comment
@Péter Török, я полностью с тобой согласен. - person Buhake Sindi; 06.09.2010

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

Однако, если вам действительно нужно это сделать, правильным способом будет TopMost реализовать Cloneable. Почему? Говорит эффективное Java 2-е издание, пункт 11:

Так что же делает Cloneable, если он не содержит методов? Он определяет поведение защищенной реализации clone класса Object: если класс реализует Cloneable, метод clone класса Object возвращает копию объекта "поле за полем"; в противном случае выдается CloneNotSupportedException. Это крайне нетипичное использование интерфейсов, и его не следует эмулировать. Обычно реализация интерфейса что-то говорит о том, что класс может сделать для своих клиентов. В случае Cloneable он изменяет поведение защищенного метода в суперклассе.

Причем Asub.clone нужно объявлять public, а не protected - иначе из внешнего мира его не вызвать. Кроме того, если вы используете Java5 или выше, для Asub.clone допустимо и желательно возвращать Asub, а не Object (и аналогично для его суперклассов).

Вы не показываете членов в классах — реализации clone в различных классах могут сильно различаться в зависимости от типов членов в этом классе. А именно, если у класса есть какие-либо изменяемые члены, вам нужно тщательно скопировать их все, иначе вы получите отдельные объекты, разделяющие их внутреннее состояние.

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

В качестве примечания: если Top a = (Top) super.clone() не является опечаткой, вы вводите зависимость от базового класса к производному классу, что не является хорошей идеей.

person Péter Török    schedule 06.09.2010
comment
Да и maybe нет, потому что Cloneable это всего лишь маркерный интерфейс. - person Buhake Sindi; 06.09.2010
comment
@The Elite Gentleman, к сожалению, Cloneable - это не просто интерфейс маркера. Смотрите мое обновление. - person Péter Török; 06.09.2010
comment
@Péter Török, таким образом, Asub глубоко клонирован, все поля, включая поля из абстрактных классов, получили новую ссылку и копию? - person setzamora; 06.09.2010
comment
@Joset, нет... раз ты звонишь super.clone(). - person Buhake Sindi; 06.09.2010
comment
@Joset, в его нынешнем виде Asub.clone() создает неглубокий клон. Значения всех полей копируются в новый объект. Этого достаточно только для примитивных (например, int) или неизменяемых (например, String) полей. Но любые изменяемые объекты должны быть глубоко скопированы вручную. - person Péter Török; 06.09.2010

Вызов super.clone() отключает виртуальный механизм, поэтому он вызывает только Object.clone()

person gpeche    schedule 06.09.2010
comment
извините, удалил другой метод, он должен быть только в TopMost - person setzamora; 06.09.2010