2009-03-19 3 views
7

Я поддерживаю старую базовую базу Java (jvm 1.4), которая, похоже, использует клонирование в качестве альтернативы экземпляру объекта, я предполагаю, что это оптимизация производительности. Вот надуманный пример:Выполняет ли клонирование улучшение производительности над конструкторами/фабричными методами?

public class Foo { 
    private SomeObject obj; // SomeObject implements Cloneable 
    public Foo() { 
    obj = new SomeObject(); 
    obj.setField1("abc"); // these fields will have the same value every time 
    obj.setField2("def"); 
    } 
    public void doStuff() { 
    SomeObject newObj = obj.clone(); // clone it instead of using a factory method 
    // do stuff with newObj 
    } 
} 

Обычные предостережений о преждевременной оптимизации несмотря на это, было это на самом деле рекомендовал идиома в какой-то момент?

+0

Кажется странным. Я бы использовал конструктор для создания нового объекта. –

ответ

3

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

Реализация clone() для выполнения мелкой копии объекта (более глубокая копия более сложна) является тривиальной по сравнению с реализацией конструктора копирования или заводского метода для выполнения той же операции. Для реализации clone() классу необходимо просто реализовать интерфейс Cloneable и переопределить метод clone() с тем, который вызывает super.clone(), который обычно вызывает Object.clone(). Object.clone() копирует каждое свойство исходного объекта в соответствующее свойство дубликата, создавая тем самым мелкую копию.

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

См. Это code example и предыдущий discussion на poor design интерфейса Cloneable.

4

Предположительно, они хотели получить копию. Возможно, они хотят передать его другой функции и не могут быть уверены, что эта функция не изменит ее. Это способ убедиться, что метод doStuff() является константой относительно состояния объекта Foo, к которому он вызван.

+0

Нанесение этого +1 +1 (если смотреть на код), оно появляется как более вероятное, чем мой более эзотерический ответ. – MarkusQ

+0

Обратите внимание, что это основная цель клонирования (если мои профессора знают, о чем они говорят). – Chris

+0

+1: Да, похоже, здесь '.clone()' - это метод Javaish pass-by-value. –

1

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

Это скорее используется, потому что семантика отличается. Клонирование предоставляет способ реализации «семантики прототипа» (например, в javascript, self и т. Д.) На языке, который обычно не имеет тенденций к этому.

+0

Как так? Я, хотя семантика прототипа просто означала, что вы можете изменить поведение конструктора или других полей или методов во время выполнения. –

+0

Клонирование позволяет вам устанавливать начальные значения и т. Д. И (с помощью делегатов) изменять поведение. Это своего рода kludge, но вы, как правило, не раздуты в стиле Self-style, просто немного сока, поэтому он часто работает на практике. – MarkusQ

0

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

Если конструктор ничего не делает, то действительно не нужно использовать клон.

Edit: добавлен код, чтобы показать, что клон не должен делать ту же работу, как конструктор:

class Main 
    implements Cloneable 
{ 
    private final double pi; 

    public Main() 
    { 
     System.out.println("in Main"); 
     // compute pi to 1,000,000,000 decimal palaces 
     pi = 3.14f; 
    } 

    public Object clone() 
    { 
     try 
     { 
      return (super.clone()); 
     } 
     catch(final CloneNotSupportedException ex) 
     { 
      throw new Error(); // would not throw this in real code 
     } 
    } 


    public String toString() 
    { 
     return (Double.toString(pi)); 
    } 

    public static void main(String[] args) 
    { 
     final Main a; 
     final Main b; 

     a = new Main(); 
     b = (Main)a.clone(); 

     System.out.println("a = " + a); 
     System.out.println("b = " + b); 
    } 
} 

Главный construtor вызывается один раз, вычислительное пи выполняется один раз.

+0

, если вы собираетесь отметить что-нибудь, по крайней мере, прокомментируйте то, что вы считаете неточным! – TofuBeer

+0

Если конструктор копирования сделал дорогостоящую работу, то клон должен был бы сделать то же самое. –

+0

Клон обходит конструктор - как вы его получите, он должен был бы сделать то же самое? – TofuBeer

2

Одна из основных проблем с конструкторами копирования заключается в том, что тип объекта должен быть известен во время компиляции.Если наследуемый класс поддерживает конструктор копирования, а конструктору передается объект производного класса, конструктор будет создавать объект базового класса, свойства базового класса которого обычно соответствуют свойствам объекта переданного объекта, но новый объект, t поддерживает любые функции, присутствующие в переданном объекте, которых нет в базовом классе.

Можно решить эту проблему несколькими способами, создав «защищенный» конструктор копирования и имеющий встроенный метод заводской копии в каждом производном классе, который вызывает собственный конструктор копирования этого класса, который, в свою очередь, вызывает конструктор копирования его базы класс. Для каждого производного класса потребуется конструктор копирования и переопределение метода копирования, независимо от того, добавляет ли он какие-либо новые поля. Если класс case использует «clone», этот дополнительный код можно исключить.

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