Clone method for Java arrays
When the clone
method is invoked upon an array, it returns a reference to a new array which contains (or references) the same elements as the source array.
So in your example, int[] a
is a separate object instance created on the heap and int[] b
is a separate object instance created on the heap. (Remember all arrays are objects).
int[] a = {1,2,3};
int[] b = a.clone();
System.out.println(a == b ? "Same Instance":"Different Instance");
//Outputs different instance
If were to modify int[] b
the changes would not be reflected on int[] a
since the two are separate object instances.
b[0] = 5;
System.out.println(a[0]);
System.out.println(b[0]);
//Outputs: 1
// 5
This becomes slightly more complicated when the source array contains objects. The clone
method will return a reference to a new array, which references the same objects as the source array.
So if we have the class Dog
...
class Dog{
private String name;
public Dog(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
and I create and populate an array of type Dog
...
Dog[] myDogs = new Dog[4];
myDogs[0] = new Dog("Wolf");
myDogs[1] = new Dog("Pepper");
myDogs[2] = new Dog("Bullet");
myDogs[3] = new Dog("Sadie");
then clone dog...
Dog[] myDogsClone = myDogs.clone();
the arrays refer to the same elements...
System.out.println(myDogs[0] == myDogsClone[0] ? "Same":"Different");
System.out.println(myDogs[1] == myDogsClone[1] ? "Same":"Different");
System.out.println(myDogs[2] == myDogsClone[2] ? "Same":"Different");
System.out.println(myDogs[3] == myDogsClone[3] ? "Same":"Different");
//Outputs Same (4 Times)
This means if we modify an object accessed through the cloned array, the changes will be reflected when we access the same object in the source array, since they point to the same reference.
myDogsClone[0].setName("Ruff");
System.out.println(myDogs[0].getName());
//Outputs Ruff
However, changes to the array itself will only affect that array.
myDogsClone[1] = new Dog("Spot");
System.out.println(myDogsClone[1].getName());
System.out.println(myDogs[1].getName());
//Outputs Spot
// Pepper
If you generally understand how object references work, it is easy to understand how arrays of objects are impacted by cloning and modifications. To gain further insight into references and primitives I would suggest reading this excellent article.
Gist of Source Code
Why clone() is the best way for copying arrays?
I would like to make some points about why clone()
is the fastest way to copy an array than System.arraycopy(..)
or others:
1. clone()
doesn't have to do the typechecking before copying a source array to the destination one as provided here. It just simple allocates new memory space and assigns the objects to it. On the other hand, System.arraycopy(..)
checks for the type and then copies an array.
2. clone()
also breaks the optimization to eliminate redundant zeroing. As you know, every allocated array in Java must be initialized with 0s
or respective default values. However, JIT can avoid zeroing this array if it sees that the array is filled right after creation. That makes it definitely faster compared to changing the copy values with existing 0s
or respective default values. While using System.arraycopy(..)
spends significant amount of time clearing and copying the initialized array. To do so I have performed some of the benchmark tests.
@BenchmarkMode(Mode.Throughput)
@Fork(1)
@State(Scope.Thread)
@Warmup(iterations = 10, time = 1, batchSize = 1000)
@Measurement(iterations = 10, time = 1, batchSize = 1000)
public class BenchmarkTests {
@Param({"1000","100","10","5", "1"})
private int size;
private int[] original;
@Setup
public void setup() {
original = new int[size];
for (int i = 0; i < size; i++) {
original[i] = i;
}
}
@Benchmark
public int[] SystemArrayCopy() {
final int length = size;
int[] destination = new int[length];
System.arraycopy(original, 0, destination, 0, length);
return destination;
}
@Benchmark
public int[] arrayClone() {
return original.clone();
}
}
Output:
Benchmark (size) Mode Cnt Score Error Units
ArrayCopy.SystemArrayCopy 1 thrpt 10 26324.251 ± 1532.265 ops/s
ArrayCopy.SystemArrayCopy 5 thrpt 10 26435.562 ± 2537.114 ops/s
ArrayCopy.SystemArrayCopy 10 thrpt 10 27262.200 ± 2145.334 ops/s
ArrayCopy.SystemArrayCopy 100 thrpt 10 10524.117 ± 474.325 ops/s
ArrayCopy.SystemArrayCopy 1000 thrpt 10 984.213 ± 121.934 ops/s
ArrayCopy.arrayClone 1 thrpt 10 55832.672 ± 4521.112 ops/s
ArrayCopy.arrayClone 5 thrpt 10 48174.496 ± 2728.928 ops/s
ArrayCopy.arrayClone 10 thrpt 10 46267.482 ± 4641.747 ops/s
ArrayCopy.arrayClone 100 thrpt 10 19837.480 ± 364.156 ops/s
ArrayCopy.arrayClone 1000 thrpt 10 1841.145 ± 110.322 ops/s
According to the outputs I am getting that clone
is almost twice fast from System.arraycopy(..)
3. Also, using manual copying method like clone()
results into faster ouput because it doesn't have to make any VM calls (unlike System.arraycopy()
).
.clone() or Arrays.copyOf()?
Update using jmh
Using jmh, I get similar results, except that clone
seems to be marginally better.
Original post
I ran a quick test for performance: clone
, System.arrayCopy
and Arrays.copyOf
have very similar performance (jdk 1.7.06, server vm).
For details (in ms), after JIT:
clone: 68
arrayCopy: 68
Arrays.copyOf: 68
Test code:
public static void main(String[] args) throws InterruptedException,
IOException {
int sum = 0;
int[] warmup = new int[1];
warmup[0] = 1;
for (int i = 0; i < 15000; i++) { // triggers JIT
sum += copyClone(warmup);
sum += copyArrayCopy(warmup);
sum += copyCopyOf(warmup);
}
int count = 10_000_000;
int[] array = new int[count];
for (int i = 0; i < count; i++) {
array[i] = i;
}
// additional warmup for main
for (int i = 0; i < 10; i++) {
sum += copyArrayCopy(array);
}
System.gc();
// copyClone
long start = System.nanoTime();
for (int i = 0; i < 10; i++) {
sum += copyClone(array);
}
long end = System.nanoTime();
System.out.println("clone: " + (end - start) / 1000000);
System.gc();
// copyArrayCopy
start = System.nanoTime();
for (int i = 0; i < 10; i++) {
sum += copyArrayCopy(array);
}
end = System.nanoTime();
System.out.println("arrayCopy: " + (end - start) / 1000000);
System.gc();
// copyCopyOf
start = System.nanoTime();
for (int i = 0; i < 10; i++) {
sum += copyCopyOf(array);
}
end = System.nanoTime();
System.out.println("Arrays.copyOf: " + (end - start) / 1000000);
// sum
System.out.println(sum);
}
private static int copyClone(int[] array) {
int[] copy = array.clone();
return copy[copy.length - 1];
}
private static int copyArrayCopy(int[] array) {
int[] copy = new int[array.length];
System.arraycopy(array, 0, copy, 0, array.length);
return copy[copy.length - 1];
}
private static int copyCopyOf(int[] array) {
int[] copy = Arrays.copyOf(array, array.length);
return copy[copy.length - 1];
}
Java cloning method does not work
The problem is the following:
- When you
clone
an array of primitives, the array object and its values are cloned. - When you
clone
an array of objects, the array object is cloned, but the cloned array will contain references to the same objects that were contained in the original array.
Now what does that mean for your case?
- Your
wtour
value seems to be an array containing primitiveint
s, so the first of the two cases above applies. I.e. both the array and it's contents are effectively copied. - Your
w
value however seems to be a multidimensional array ofint
s. In practice this means that it's actually an array containing array objects, hence the second case applies. Although your top-level array object is copied, the copied array contains references to the same second-level array objects as the original array.
A similar issue and possible solutions are discussed here.
Update
As requested in the comments, a straightforward implementation could look like this. Note that this is completely untested:
public static int[][][] copy(int[][][] source) {
int[][][] target = source.clone();
for (int i = 0; i < source.length; i++) {
target[i] = source[i].clone();
for (int j = 0; j < source[i].length; j++) {
target[i][j] = source[i][j].clone();
}
}
return target;
}
Write a generic method to copy an array
You can use the concept of reflection to write a generic copy method that can determine type at runtime. In a nutshell, reflection is the ability to inspect classes, interfaces, fields and methods at runtime without knowing the names of classes, methods etc at compile time.
java.lang.Reflect together with java.lang.Class comprise the Java Reflection API. This method uses both of those classes and some of their methods to make a generic arrayCopy
method that will find out the type for us.
More info: What is reflection and why is it useful?
Syntax that may be unfamiliar
Class<?>
is using a wildcard operator ?
which basically says that we can have a Class
object of unknown type - a generic version of class Class
.<T>
is a generic operator that stands for raw typeArray
The Array class provides static methods to dynamically create and access Java arrays. i.e. This class contains methods that allow you to set and query the values of array elements, determine the length of the array, and create new instances of arrays. We are going to use Array.newInstance()
Methods from reflection API
getClass ()
- returns an array containing Class objects representing all public classes and interfaces that are members of the represented class object.getComponentType()
- returns the class representing the component type (what type i.e. int, , etc) of the array.newInstance()
- Gets a new instance of an array.private <T> T[] arrayCopy(T[] original) {
//get the class type of the original array we passed in and determine the type, store in arrayType
Class<?> arrayType = original.getClass().getComponentType();
//declare array, cast to (T[]) that was determined using reflection, use java.lang.reflect to create a new instance of an Array(of arrayType variable, and the same length as the original
T[] copy = (T[])java.lang.reflect.Array.newInstance(arrayType, original.length);
//Use System and arraycopy to copy the array
System.arraycopy(original, 0, copy, 0, original.length);
return copy;
}
Related Topics
How to Reference a Method in Javadoc
Why Maven? What Are the Benefits
Sharing a Persistence Unit Across Components in a .Ear File
How to Deserialize a List Using Gson or Another JSON Library in Java
Making a Log4J Console Appender Use Different Colors for Different Threads
Block()/Blockfirst()/Blocklast() Are Blocking Error When Calling Bodytomono After Exchange()
Is There Any Good and Free Date and Time Picker Available for Java Swing
Running Java Gives "Error: Could Not Open 'C:\Program Files\Java\Jre6\Lib\Amd64\Jvm.Cfg'"
Why Are Java 8 Lambdas Invoked Using Invokedynamic
How to Run a Java Class in a Package
Can a Class Have No Constructor
How to Read a Text-File Resource into Java Unit Test
Find Duplicate Element in Array in Time O(N)
How to Solve the "A Generic Array of T Is Created for a Varargs Parameter" Compiler Warning
Why Does Java App Crash in Gdb But Runs Normally in Real Life