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?

sk.
  • 6,336
  • 5
  • 38
  • 46

5 Answers5

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.

Lou Franco
  • 87,846
  • 14
  • 132
  • 192
  • Bumping this up +1 'cause (after looking at the code) it's appears as or more likely to apply than my more esoteric answer. – MarkusQ Mar 19 '09 at 19:57
  • Note that this is the primary purpose of cloning (assuming my professors knew what they were talking about). – Chris Nov 11 '09 at 19:10
  • +1: Yup, it seems here `.clone()` is the Javaish way of pass-by-value. – Steve Schnepp Nov 11 '09 at 19:44
  • 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. – Derek Mahar Nov 13 '09 at 21:13
  • @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. – supercat Oct 24 '10 at 21:14
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.

Community
  • 1
  • 1
Derek Mahar
  • 27,608
  • 43
  • 124
  • 174
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.

supercat
  • 77,689
  • 9
  • 166
  • 211
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.

MarkusQ
  • 21,814
  • 3
  • 56
  • 68
  • How so? I though prototype semantics just meant you could alter the behaviour of the constructor or other fields or methods at runtime. – sk. Mar 19 '09 at 19:39
  • 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. – MarkusQ Mar 19 '09 at 19:58
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.

TofuBeer
  • 60,850
  • 18
  • 118
  • 163
  • if you are going to mark something down at least comment on what you feel is inaccurate about it! – TofuBeer Mar 19 '09 at 17:54
  • If the copy constructor did expensive work, then clone would have to do the same. – Tom Hawtin - tackline Mar 19 '09 at 18:02
  • clone bypasses the constructor - how do you get it would have to do the same? – TofuBeer Mar 19 '09 at 18:11
  • @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. – TofuBeer Mar 19 '09 at 18:24