Why Do I Need to Copy an Array to Use a Method on It

Why do I need to copy an array to use a method on it?

When you use Array(arrayLength) to create an array, you will have:

a new JavaScript array with its length property set to that number (Note: this implies an array of arrayLength empty slots, not slots with actual undefined values).

The array does not actually contain any values, not even undefined values - it simply has a length property.

When you spread an iterable object with a length property into an array, spread syntax accesses each index and sets the value at that index in the new array. For example:

const arr1 = [];arr1.length = 4;// arr1 does not actually have any index properties:console.log('1' in arr1);
const arr2 = [...arr1];console.log(arr2);console.log('2' in arr2);

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()).

Is it necessary to deep copy an array in java?

You are not breaking OOP principals. However, you are breaking principals of functional programming. Functional programming views leaking of access as losing of control.

Whether or not you want to practice functional programming is up to you, Java doesn't take a stance in that matter.

You may want to consider if it's important not to leak access for this particular class. If you find it important not to leak access then make this class immutable.

You can also guard the instance variables. In this scenario any possible changes to the variables must be handled by the instance class. However, the instance could be modified from separate contexts and result in loss of control. For this reason functional programming only allows immutable classes.

Copy array by value

Use this:

let oldArray = [1, 2, 3, 4, 5];

let newArray = oldArray.slice();

console.log({newArray});

Is there a function to copy an array in C/C++?

Since C++11, you can copy arrays directly with std::array:

std::array<int,4> A = {10,20,30,40};
std::array<int,4> B = A; //copy array A into array B

Here is the documentation about std::array

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

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 type
  • ArrayThe 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



    Leave a reply



    Submit