41

When copying an entire array, I've often seen people write:

int[] dest = new int[orig.length];
System.arraycopy(orig, 0, dest, 0, orig.length);

But it seems to me there is no reason to favor this over:

int[] dest = orig.clone();

They're both shallow copies anyway. Probably these folks just don't realize that clone exists. So is there any reason not to use clone?

Neil Traft
  • 18,367
  • 15
  • 63
  • 70
  • 1
    `System.arraycopy` copies each element from `orig` to `dest`, which then is a deep copy, not shallow. – Joonas Pulakka Aug 24 '11 at 17:08
  • 13
    It makes `dest[0]` refer to the same object as `orig[0]`. So if `orig[0]` is an array, `dest[0]` will contain the exact same array instance; it will not clone the sub-array. This is not a deep copy. Is this not correct? – Neil Traft Aug 24 '11 at 17:13
  • 1
    In your example, you used `int` primitives. Then `dest[0]` gets the value that `orig[0]` had at the time of copying. If `orig[0]`'s *value* changes after that, it doesn't affect `dest[0]`'s *value* any more. If the value is an object reference (as would be in an `Object[]` array (whose elements could be e.g. `int[]` arrays), then the object may of course mutate. – Joonas Pulakka Aug 24 '11 at 17:15
  • 9
    Sure, but my example was just an example. The point is that `arraycopy` is no "deeper" than `clone`, whatever your meaning of deep/shallow might be. – Neil Traft Aug 24 '11 at 17:21

5 Answers5

40
  • clone() makes a distinct copy of the first array with its own reference.
  • System.arraycopy() uses JNI (Java Native Interface) to copy an array (or parts of it), so it is blazingly fast, as you can confirm here;
  • clone() creates a new array with the same characteristics as the old array, i.e., same size, same type, and same contents. Refer to here for some examples of clone in action;
  • manual copying is, well, manual copying. There isn't much to say about this method, except that many people have found it to be the most performant.
  • arraynew = arrayold doesn't copy the array; it just points arraynew to the memory address of arrayold or, in other words, you are simply assigning a reference to the old array.
  • 1
    Care to explain the arraycopy() comment? – ZenMaster Aug 24 '11 at 16:55
  • 2
    You didn't answer my question. Also, I would hope that `clone` is just as fast as `arraycopy`. Is it not also native? – Neil Traft Aug 24 '11 at 17:10
  • 2
    @Neil: Clone is slower. See first link. –  Aug 24 '11 at 17:11
  • Looking at the code in the System.arraycopy() article there has been no "warm-up" time so not sure if this is a fair microbenchmark – luketorjussen Aug 24 '11 at 17:13
  • 5
    @Code Monkey: From the article itself: "Using clone() for copying arrays is less code and the performance difference is, as we saw, only significant for tiny arrays. I think that in future I will rather use clone() than System.arrayCopy()." – Neil Traft Aug 24 '11 at 17:19
  • `System.arraycopy` does not use JNI to copy arrays - rather it is implemented as intrinsic (generally even faster). At that is the case on modern HotSpot JVMs such as OpenJDK. – BeeOnRope May 28 '14 at 03:03
  • It doesn't answer the question, the real answer is in the comment by @NeilTraft – Krzysztof Krasoń Mar 24 '16 at 20:08
  • @user195488 -- you did not read through your own link https://www.javaspecialists.eu/archive/Issue124.html if you look at the very end of that article it reveal that for small arrays clone shows better performance. and yes both clone() and System.arraycopy() are using JNI -- please look at specifier "native" at front of the method. – Dmitriy Pichugin May 03 '20 at 19:18
  • @DmitriyPichugin your comment is wrong here: `it reveal that for small arrays clone shows better performance`. The article shows that for small arrays clone has _worse_ performance because it adds checks to prevent memory leaks for Object arrays. In other words... in most cases you should use clone() (or Arrays.copyOf()) but for better performance on _small_ arrays (< 1000) of _primitive_ objects System.arraycopy() is faster and safe to use (at least it was when the article was written in 2006 using Java 5) – egerardus May 10 '21 at 18:10
10

No. If you're really microbenchmarking, then maybe, depending on what JVM you're running. But in actuality, no.

Neil Traft
  • 18,367
  • 15
  • 63
  • 70
8

I happened to look at this question when I was pondering on the same doubt. I feel that the arraycopy() is a method to be used when the array is predefined (i.e. memory is already allocated). Thus, the overhead associated with memory allocation is not repeated.

For example, imagine a case when you have defined a large array which is updated periodically. Then using clone() will recreate a array of required size every time the array is copied. However, arraycopy() uses the pre-allocated memory space.

Thus arraycopy() is more efficient in certain scenarios compared to clone(). On the other hand clone() results in a compact code.

Sourabh Bhat
  • 1,793
  • 16
  • 21
6

Using System.arraycopy or Arrays.copyOf instead of clone() makes your code more explicit and therefore easier to understand. It says "I'm copying an array" as opposed to "I'm (magically) copying some kind of object".

Explicit is better than implicit. - The Zen of Python

But the main argument in favor of the Arrays.copyOf methods (and against clone()) is type-safety, the lack of which is probably the biggest gotcha of clone() that could lead to subtle bugs if you're not careful that the object you're cloning has the exact array component type that you want.

Let's look at the JDK-6260652 bug for example. The culprit was clone() being used in Arrays.ArrayList to implement Collection.toArray() (which is declared to return Object[]). This particular ArrayList is a private class in java.util.Arrays instantiated by Arrays.asList(T... a) using a as its backing array without caring about the actual type of a, which might have been a String[] or Integer[] (or whatever else that's not actually Object[]). The problem with its toArray() method returning a.clone() here is that a programmer might end up using Arrays.ArrayList.toArray() at some point to do something like this:

List<String> lst = Arrays.asList("a", "b", "c");
// ... many lines of code later ...
Object[] arr = lst.toArray();
// ... at this point don't care about the original type of elements in lst ...
arr[0] = 123;  // ArrayStoreException - WTF?!
// arr is an Object[] so should be able to store Integer values!

This kind of bug can go unnoticed for years because the usage pattern illustrated above is not common. Just consider that the Collections framework has been around since JDK 1.2 (1998) but this particular issue wasn't reported until 2005 (and 10 years later someone discovered a similar issue in a different part of the JDK). The patch for JDK-6260652 (released in Java 9) simply replaces a.clone() with Arrays.copyOf(a, a.length, Object[].class).


To summarize, my arguments in favor of using the array copy methods instead of clone() are:

  • System.arraycopy:
    1. more explicit
  • Arrays.copyOf:
    1. more explicit
    2. and provides type-safety
typeracer
  • 759
  • 8
  • 11
2

Just guessing here, but there might be a good reason to use System.arraycopy because different JVM's could conceivably implement them in a way that takes advantage of native abilities of the underlying system for a performance boost.

For example, a JVM implementation could use a native library call like memcpy which could potentially take advantage of some memory controller tricks to perform the action in some incredibly fast and clever way. However, the Object.clone implementation might not be a good candidate for such optimization due to its virtual nature.

maerics
  • 151,642
  • 46
  • 269
  • 291
  • 1
    arrayCopy uses JNI to copy; it is really fast. –  Aug 24 '11 at 17:00
  • Well, the particular JVM implementation they are benchmarking apparently does but I don't think you can say categorically that *all* JVMs do the same. – maerics Aug 24 '11 at 17:03
  • 2
    I'm a bit confused on this. The JVM implements both arraycopy and clone, right? So why wouldn't the implementations be similar? What do you mean "its virtual nature?" – Neil Traft Aug 24 '11 at 17:23
  • 2
    @Neil Traft: I'm guessing that the JVM implements `arraycopy` as a native method but `Object.clone` is implemented in the Java language itself (as part of the [standard class library](http://en.wikipedia.org/wiki/Java_Class_Library)). By "virtual nature" I mean that the root `Object` class implementation has a "clone" method but subclasses override them with their own implementation, so perhaps this "virtual method dispatch" complicates the ability to do the sort of optimization tricks I imagine. – maerics Aug 24 '11 at 17:36
  • 4
    @maerics: But... when I look at the source code for Object.java from the Sun JDK distribution, it says "protected **native** Object clone()". – Neil Traft Aug 25 '11 at 16:39
  • @Neil Traft: well, looks like my guess was wrong =) I suppose they could do the same fancy optimization tricks in `Object.clone`. Of course, this is all totally implementation dependent. Each JVM might be different from the next. – maerics Aug 25 '11 at 16:50