Обеспечивает ли клонирование улучшение производительности по сравнению с конструкторами / фабричными методами? - PullRequest
7 голосов
/ 19 марта 2009

Я поддерживаю более старую 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
  }
}

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

Ответы [ 5 ]

4 голосов
/ 19 марта 2009

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

3 голосов
/ 11 ноября 2009

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

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

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

См. пример кода и предыдущее обсуждение о плохом дизайне интерфейса Cloneable.

2 голосов
/ 09 марта 2011

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

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

1 голос
/ 19 марта 2009

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

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

0 голосов
/ 19 марта 2009

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

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

Редактировать: добавлен код, показывающий, что клон не должен выполнять ту же работу, что и конструктор:

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);
    }
}

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

...