11

I'm trying to understand what's happening underneath the clone() method in java, I would like to know how is better than doing a new call

public class Person implements Cloneable {

    private String firstName;
    private int id;
    private String lastName;

    //constructors, getters and setters

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person p = (Person) super.clone();
        return p;
    }

}

this is my clone code i would like to know what's happening underneath and also what's the difference between a new call because.

this is my client code

    Person p = new Person("John", 1, "Doe");
    Person p2 = null;
    try {
         p2 = (Person) p.clone();
    } catch (CloneNotSupportedException ex) {
        Logger.getLogger(clientPrototype.class.getName()).log(Level.SEVERE, null, ex);
    }
    p2.setFirstName("Jesus");
    System.out.println(p);
    System.out.println(p2);
Andrii Abramov
  • 10,019
  • 9
  • 74
  • 96
lfernandez93
  • 143
  • 1
  • 1
  • 7
  • Why do you think that clone() has better performance than object creation? That's not true. – yole Feb 25 '15 at 19:22
  • 3
    It's also [not a good](http://stackoverflow.com/questions/2326758/how-to-properly-override-clone-method#answer-2326801) idea to use `clone()` in the first place. – Adam Stelmaszczyk Feb 25 '15 at 19:23
  • What would you use instead of clone, also, why is not true clone has better performance? – lfernandez93 Feb 27 '15 at 05:47
  • 1
    One non-performance-related advantage of `.clone()` (assuming it uses `Object.clone()` underneath) is that it produces an object with the same runtime class as the object it is called on, whereas if you use `new` you would be hard-coding at compile-time the class of object you are creating, which may not be the same as the exact runtime class of the object (the object's class can be a subclass of the compile-time type of a variable that points to it). – newacct Jun 24 '17 at 06:16
  • As always when talking about `clone`, try to **avoid it at all cost**. It is a broken feature, super easy to introduce bugs and extremely hard to implement correct. And even harder to maintain a correct implementation with inheritance in place (*Effective Java* has a nice read on that topic). There are much more safer and better ways for creating copies. For example by introducing a *copy constructor* to your class. – Zabuzard May 17 '19 at 19:19

6 Answers6

11

If you need a copy, call clone(), if not, call a constructor.
The standard clone method (java.lang.Object.clone()) creates a shallow copy of the object without calling a constructor. If you need a deep copy, you have to override the clone method.
And don't worry about performance.
Performance depends on the contents of the clone method and the constructors and not from the used technique(new or clone) itself.

Edit: Clone and constructor are not really alternatively to each other, they fullfill different purposes

Gren
  • 1,850
  • 1
  • 11
  • 16
  • So what you are saying is new an object and cloning an object has the same impact? – lfernandez93 Feb 27 '15 at 05:46
  • No, the impact depends on the contents of the constructor and the clone method. If your class has only few members, a simple default-ctor and no override of clone(), the impact `may` be similar. My recommendation is to use clone only if you need a copy of an existing object. Clone and constructor are not really alternatively to each other, they fullfill different purposes. – Gren Feb 27 '15 at 09:21
  • so if i want a clone of an existing object will it have more performance than newing a new object with the same values as my object ? – lfernandez93 Feb 27 '15 at 17:14
  • That cannot be answered generally. If your class has only primitives and you don't override clone() and your constructor processes some work, clone() is `maybe` faster. But this discussion is a little bit useless, because you should use the technique you need, and not the fastest one or `maybe fastest` one. Construction and cloning are different concepts and you should choose the tecnique which fits your needs. – Gren Feb 27 '15 at 17:30
  • mmm, so okay but let's say that i want the fastest in this case, would clone make it faster somehow? – lfernandez93 Feb 27 '15 at 20:07
  • Test it. Create a million of objects with the contructor and another million with clone() with time measurement. But you have to do it for all types of objects you want to handle. – Gren Mar 01 '15 at 09:29
7

I have created simple benchmark for class Person:

public class Person {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

And got the following results:

Benchmark             Mode  Cnt     Score       Error   Units

MyBenchmark.viaClone  avgt   10     10.041 ±    0.059   ns/op
MyBenchmark.viaNew    avgt   10      7.617 ±    0.113   ns/op

This simple benchmark demonstrates that instantiating new object and setting corresponding properties from source object takes 25% less time than cloning it.

Andrii Abramov
  • 10,019
  • 9
  • 74
  • 96
  • I submitted a PR to your repo, added a Clone Constructor method to the benchmark. When benchmarking on a macbook pro w/ jdk11, "Score" was ~4 ns/op across all 3 methods, performance difference negligible. https://github.com/aaabramov/benchmark-it/pull/12 – Jon L. Apr 26 '21 at 05:46
6
public void testPerformance(){
    SimpleDateFormat sdf  = new SimpleDateFormat("yyyy-MM-dd");
    long start = System.currentTimeMillis();
    for(int i = 0; i < 1000000; i++){
        SimpleDateFormat localSdf = (SimpleDateFormat)sdf.clone();
    }
    System.out.println("Cloning : " + (System.currentTimeMillis() - start) + " ms");

    start = System.currentTimeMillis();
    for(int i = 0; i < 1000000; i++){
        Object localSdf = new SimpleDateFormat("yyyy-MM-dd");
    }
    System.out.println("Creating : " + (System.currentTimeMillis() - start) + " ms");

}

Cloning : 302 ms Creating : 885 ms

  • 2
    The user wanted to know what is going on under the hood of the clone function not just the performance. – Roberto Anić Banić Jun 19 '17 at 12:20
  • 2
    It is not about object cloning vs constructor performance, it's more about `SimpleDateFormat`, because this specific constructor is very heavy. I would recommend to have it's static instance for reuse. – kairius May 24 '18 at 09:59
  • @kairius static has a whole host of haters who conflate it with the sins of global state, since almost any context might be a reentrant one. Final is a friend. – glumplum Feb 18 '19 at 20:23
  • I'm not questioning programming practices, I just mean that SimpleDateFormat constructor is very heavy and slow. See https://askldjd.com/2013/03/04/simpledateformat-is-slow/ – kairius Feb 20 '19 at 11:25
1

Joachim is right. If you need copy use Clone, If you need a seprate object (for a seprate person) you should use new and create a new Object instead.

'More Performance' is subjective and may not be the right term here. What happens in clone is the underlying objects are shared, i.e. they have 2 seprate references to the same memory location. So effectively you save up creating objects and memory. Remember Deep copy / Shallow Copy?

Kedar Parikh
  • 1,241
  • 11
  • 18
  • can you explain me more this thing you said about 2 object en memory having the same memory location? how come then if i edit one the other one is not changed? wouldn't it be two references with two separate memory location? – lfernandez93 Feb 27 '15 at 17:16
  • Here is a decent explanation: http://javarevisited.blogspot.in/2013/09/how-clone-method-works-in-java.html – Kedar Parikh Mar 02 '15 at 06:37
1

My requirement is to create 1000's of object for a class. All those objects shares most of the properties in common. Hence I decided to create one base object with common properties and clone it and on cloned object set object specific properties. What will be the performance impact on this?. I tried out same example as above, with different approach and I noticed no much stable performance difference. Here are my code and results.

import java.util.*;
import java.util.stream.*;
import java.text.*;
public class Test{
    public static void main(String[] args){

        try{
            SimpleDateFormat sdf  = new SimpleDateFormat("yyyy-MM-dd");
            long start = System.currentTimeMillis();
            SDFHolder holder = new SDFHolder();
            holder.setSdf(sdf);
            for(int i = 0; i < 1000000; i++){
                SDFHolder locHolder = (SDFHolder)holder.clone();
            }
            System.out.println("Cloning : " + (System.currentTimeMillis() - start) + " ms");
            start = System.currentTimeMillis();
            for(int i = 0; i < 100000000; i++){
                SDFHolder locHolder = new SDFHolder();
                locHolder.setSdf(sdf);
            }
            System.out.println("Creating : " + (System.currentTimeMillis() - start) + " ms");
        } catch(Exception e){
            e.printStackTrace();
        }
    }
}
class SDFHolder implements Cloneable {
    private SimpleDateFormat sdf;

    public void setSdf(SimpleDateFormat sdf){
        this.sdf = sdf;
    }

    public SimpleDateFormat getSdf(){
        return this.sdf;
    }

    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}

And results are

C:\Users\thangaraj.s\Desktop>java Test
Cloning : 15 ms
Creating : 0 ms

C:\Users\thangaraj.s\Desktop>java Test
Cloning : 16 ms
Creating : 0 ms

C:\Users\thangaraj.s\Desktop>java Test
Cloning : 0 ms
Creating : 15 ms

C:\Users\thangaraj.s\Desktop>java Test
Cloning : 0 ms
Creating : 16 ms

C:\Users\thangaraj.s\Desktop>java Test
Cloning : 16 ms
Creating : 0 ms

So, I don't think there is a huge performance impact on these but gives more concise code in-case of my requirement.

thangaraj
  • 525
  • 5
  • 5
0

It also depends on the number of fields and complex stored structures that will need to be cloned using the deep method. I came across a similar task where you need to give away a typical object as quickly as possible in 99% of cases and the object is very complex in content. Therefore, I am now considering the option to store the prepared binary object as a response template, and clone it and deploy it to the desired class. In theory, it can be faster, especially cloning for structurally complex objects. but I don't know how effective it will be to convert a cloned object from a binary format to a class

Alex Bo
  • 1
  • 1