Does cloning provide a performance improvement over constructors/factory methods?

南楼画角 提交于 2019-12-22 05:05:14

问题


I'm maintaing an older Java code base (jvm 1.4) that seems to use cloning as an alternative to object instantiation, I'm guessing as a performance optimization. Here's a contrived example:

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

The usual caveats about premature optimization notwithstanding, was this actually a recommended idiom at some point?


回答1:


One reason to invoke clone() instead of the copy constructor or a factory method is that none of the other options may be available.

Implementing clone() to perform a shallow object copy (deep copy is more involved) is trivial compared to implementing a copy constructor or a factory method to perform the same operation. To implement clone(), a class need simply implement the Cloneable interface and override method clone() with one that invokes super.clone() which usually invokes Object.clone(). Object.clone() copies every property of the original object into the corresponding property of the duplicate, thus creating a shallow copy.

Though implementing clone() is straightforward, it is still easy to forget to implement Cloneable. Consequently, a potential risk of using clone() to duplicate an object is that if the class of that object does neglect to implement Cloneable and clone() invokes Object.clone() either directly or indirectly, it will throw CloneNotSupportedException.

See this code example and a previous discussion on the poor design of the Cloneable interface.




回答2:


Presumably they wanted a copy. Perhaps they want to pass it to another function, and can't be sure that that function won't change it. It's a way of making sure that the method doStuff() is const with respect to the state of the Foo object it's called on.




回答3:


One major problem with copy constructors is that the type of the object has to be known at compile time. If an inheritable class supports a copy constructor, and the constructor is passed a derived-class object, the constructor will produce a base-class object whose base-class properties generally match those of the passed-in object, but the new object won't support any features that were present in the passed-in object that weren't present in the base class.

It's possible to solve this problem somewhat by making a copy constructor "protected", and having an overridable factory copy method in every derived class which calls that class' own copy constructor, which in turn calls the copy constructor of its base class. Every derived class will need a copy constructor and an override of the copy method, though, whether or not it adds any new fields. If the case class uses "clone", this extra code can be eliminated.




回答4:


It may be a performance optimization, depending on how much work is done in the constructors.

It's more likely used because the semantics are different. Cloning provides a way to implement "prototype semantics" (like in javascript, self, etc.) in a language that doesn't normally tend that way.




回答5:


If the SomeObject constructor does expensive work, such as grabbing something from a database or parsing something, or reading something from a file then the clone would make sense to avoid doing the work.

If the constructor does nothing then there really is no need to use clone.

Edit: added code to show that clone does not have to do the same work as the constructor:

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

The Main construtor is called once, the computing pi is performed once.



来源:https://stackoverflow.com/questions/663079/does-cloning-provide-a-performance-improvement-over-constructors-factory-methods

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!