Как клонировать объект, тип которого вы не знаете? - PullRequest
1 голос
/ 19 августа 2010

легче объяснить в коде, поэтому здесь

Object anObj;
anObj = new MyObj();
anObj = new Rectangle();
anObj.clone();//this doesnt exist because its on the root Object class

что я могу использовать вместо метода Object.clone () в этом примере?

----------------------- дополнительная информация ---------------------- --------

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

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

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

public Object clone() {//i copied from 'thelost's answer
    try { 
        CloningExample copy = (CloningExample)super.clone(); 
        copy.names = (LinkedList)names.clone(); 
        return copy; 
    } catch (CloneNotSupportedException e) { 
        return null; 
    } 
}

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

static findTypeAndCopy(Object thisobj){ 
    if(thisobj==null) 
        return null;

    if(thisobj instanceOf MyObj1){ 
        return ((MyObj1)thisobj).clone(); 
    }else if(thisobj instanceOf MyObj2){ 
        return ((MyObj2)thisobj).clone(); 
    ... 
    etc
}

???

Ответы [ 6 ]

4 голосов
/ 19 августа 2010

Вы, похоже, поняли, что Cloneable в Java не работает.

Вот несколько цитат из интервью с Джошем Блохом , автора Effective Java 2nd Edition :

Если вы читали статью о клонировании в моей книге, особенно если вы читаете между строк, вы поймете, что я думаю, clone глубоко нарушен. Есть несколько недостатков дизайна, самый большой из которых заключается в том, что интерфейс Cloneable не имеет метода clone. А это значит, что это просто не работает: создание чего-либо Cloneable ничего не говорит о том, что вы можете с ним сделать. Вместо этого он говорит что-то о том, что он может сделать внутри. Он говорит, что если при повторном вызове super.clone он вызовет метод Object clone, этот метод вернет копию поля оригинала.

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

Вот некоторые цитаты из книги, Пункт 11: Переопределить clone разумно :

[...] вам лучше предоставлять альтернативные средства копирования объектов или просто не предоставлять такую ​​возможность.

[...] Хороший подход к копированию объектов заключается в предоставлении конструктора копирования или фабрики копирования . Конструктор копирования - это просто конструктор, который принимает единственный аргумент, тип которого является классом, содержащим конструктор:

public Yum(Yum yum);

Фабрика копирования - это static фабричный аналог конструктора копирования:

public static Yum newInstance(Yum yum);

Похожие вопросы


Альтернатива: Cloneable 2.0

Если вы действительно настаиваете на том, чтобы функциональность, подобная Cloneable, не нарушалась, вы можете написать что-то вроде этого (обобщено для дополнительного джаза):

public class DupableExample {

    interface Dupable<T> {
        T dup();
    }   
    static class Sheep implements Dupable<Sheep> {
        Sheep(Sheep sheep) { }
        @Override public Sheep dup() {
            return new Sheep(this);
        }
    }
    public static void main(String[] args) {
        Dupable<?> dupable = new Sheep(null);
        System.out.println(dupable);
        System.out.println(dupable.dup());

        // no cast needed
        Sheep dolly2 = new Sheep(null).dup();
    }
}

Вывод должен быть примерно таким (, как видно на ideone.com ):

DupableExample$Sheep@{some hexadecimal code}
DupableExample$Sheep@{a different hexadecimal code, in all likelyhood}

Так что теперь, получив любую Dupable<T>, вы можете вызвать T dup(), чтобы получить, как вы ожидаете, дублированную копию.

Это просто подтверждение концепции: в реальной реализации ваш конструктор копирования / фабрика копирования / любой другой механизм копирования фактически будет иметь реализованную логику копирования, и Dupable<T> будет public верхнего уровня interface.

4 голосов
/ 19 августа 2010

Лучшая идея - избегать клонирования, так как не работает.
Cloneable интерфейс не имеет метода clone.Метод clone определяется как protected в Object классе.Поэтому для вызова clone вам нужно знать тип объекта, чтобы иметь доступ к clone.Лучшая идея - либо конструктор копирования (как рекомендует Блох), либо сериализация и десериализация (например, через XML).
Может быть, вы можете получить доступ к clone с отражением, но я не уверен.И я не одобряю это.

0 голосов
/ 19 августа 2010
interface PublicCloneable extends Cloneable{
    public Object clone();
}

class MyObject implements PublicCloneable {
    public Object clone() {
        return super.clone();
    }
}

class MainObject {
    public static void main(String[] params) {
        Object m = new MyObject();

        if (m instanceof PublicCloneable) {
            Object c = m.clone();
        }
    }
}
0 голосов
/ 19 августа 2010

Вы не можете точно знать, что класс способен клонировать, потому что clone() - это метод из Object.Лучшее, что вы можете сделать, это проверить, является ли класс Клонируемым .Обычно, когда класс Cloneable , это означает, что разработчик отверг метод clone().

Но даже в этом случае Object не может вызвать этот метод.

Есть решение для отражения.Но, как сказано в документе:

Даже если метод клона вызывается рефлексивно, нет гарантии, что он будет успешным.

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

0 голосов
/ 19 августа 2010

Как уже говорили другие: Clonable не работает, и вы должны рассмотреть другие варианты, такие как конструкторы копирования.Сказав это, вот решение, которое должно работать, если вы действительно должны использовать clone ():

Object clone = null;
if(anObj instanceof Clonable) {
    Method cloneMethod = anObj.getClass().getMethod("clone");
    /*
     * TODO: Handle the case where an object is cloneable but 
     * does not have a public clone() method.
     */
    clone = cloneMethod.invoke(anObj);
} else {
    throw new RuntimeException("can't clone object");
}

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

0 голосов
/ 19 августа 2010

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

И здесь и пример того, как реализовать это самостоятельно.

...