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

5

7

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?

Soapbox answered 19/3, 2009 at 17:7 Comment(1)
It seems odd. I would use the constructor for new object instantiation.Coetaneous
S
3

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.

Spondee answered 11/11, 2009 at 19:3 Comment(0)
A
4

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.

Aphorize answered 19/3, 2009 at 17:10 Comment(5)
Bumping this up +1 'cause (after looking at the code) it's appears as or more likely to apply than my more esoteric answer.Ician
Note that this is the primary purpose of cloning (assuming my professors knew what they were talking about).Shipmaster
+1: Yup, it seems here .clone() is the Javaish way of pass-by-value.Natelson
Yes, but the question asks why the code author chose to use clone() instead of alternative ways to create a copy such as through a copy constructor or factory method.Spondee
@Derek Mahar: A properly-designed clone method will return an object of the same type as the original. Neither a copy constructor nor a factory method can do either of those things unless a type supports an overridable function to return a factory that will return objects of its own type.Scraperboard
S
3

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.

Spondee answered 11/11, 2009 at 19:3 Comment(0)
S
2

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.

Scraperboard answered 9/3, 2011 at 18:21 Comment(0)
I
1

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.

Ician answered 19/3, 2009 at 17:10 Comment(2)
How so? I though prototype semantics just meant you could alter the behaviour of the constructor or other fields or methods at runtime.Soapbox
Cloning lets you set initial values, etc. and (by using delegates) change behavior as well. It is kind of a kludge, but you don't generally full blown Self-style semantics, just a little of the juice, so it often works in practice.Ician
V
0

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.

Visit answered 19/3, 2009 at 17:27 Comment(4)
if you are going to mark something down at least comment on what you feel is inaccurate about it!Visit
If the copy constructor did expensive work, then clone would have to do the same.Exclave
clone bypasses the constructor - how do you get it would have to do the same?Visit
@Tom, yes you could do it with a copy constructor instead of calling super.clone... but if it did expensive work instead of a simple copy AND the work wasn't required then it would be poorly coded.Visit

© 2022 - 2024 — McMap. All rights reserved.