An in-depth analysis of array copying in Java: System.arraycopy, Arrays.copyOf and Arrays.copyOfRange

When it comes to working with arrays in Java, there are many methods to choose from, some of which include System.arraycopy(), Arrays.copyOf()and Arrays.copyOfRange(). These methods allow you to copy data between different arrays, but there are some subtle differences between them. In this blog post, we’ll dive into these methods so you know when to use them and how to use them correctly.

System.arraycopy()

System.arraycopyMethods are native methods in Java, and their actual implementation is provided by the underlying implementation of the Java virtual machine.

public static native void arraycopy(Object src,  int  srcPos,
                                    Object dest, int destPos,
                                    int length);

Parameter Description:

  • src: source array
  • srcPos: starting position in the source array
  • dest: target array
  • destPos: starting position in the target array
  • length: the number of elements to be copied

System.arraycopy()The performance of the method is very high because it is implemented by the underlying code and can take advantage of the characteristics of the hardware for fast data copying. It's usually much faster than using a loop to copy array elements one by one.

System.arraycopy()Can be used for up or down casts, but should be used with caution to ensure data type compatibility and runtime type checking. If the data types do not match, although it can be compiled, a runtime exception will occur at runtime java.lang.ArrayStoreException. The best practice is to try to avoid unnecessary type conversions to keep your code clear and maintainable.

Example:

public static void main(String[] args) {

    String[] strArray = new String[]{"xj1","xj2","xj3","xj4","xj5"};
    String[] strArrayCopy = new String[5];
    System.arraycopy(strArray,0,strArrayCopy,0,3);

    //向下转型
    TestEntity[] testArray = new TestChildEntity[]{new TestChildEntity("xiuji","xj")} ;
    TestChildEntity[] testChildArrayCopy = new TestChildEntity[2];

    System.arraycopy(testArray,0,testChildArrayCopy,0,1);

    System.out.println(Arrays.toString(strArrayCopy));
    System.out.println(Arrays.toString(testChildArrayCopy));
}

operation result

[xj1, xj2, xj3, null, null]
[TestChildEntity{nickName='xj'name='xiuji'}, null]

Arrays.copyOf()

grammar:

No type conversion

copyOf(T[] original, int newLength)

conversion type

copyOf(U[] original, int newLength, Class<? extends T[]> newType)

Parameter Description:

  • original: the original array to be copied.
  • newLength: The length of the new array, which can be longer or shorter than the length of the original array.
  • newType: The type of the new array, which is a Class object, usually an array class. It is used to determine the type of the new array.

Source code:

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
     
    @SuppressWarnings("unchecked")
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);这是一个三元条件运算符,
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}
  • @SuppressWarnings("unchecked"): This annotation is used to tell the compiler to ignore unchecked conversion warnings. Because a type conversion is performed in this method, use this annotation to suppress the warning.

  • T[] copy = ((Object)newType == (Object)Object[].class): This ternary conditional operator creates a new array copy based on the type of newType. If newType is Object[].class, create a new array of type Object; otherwise, use the Array.newInstance() method to create a new array whose type is determined by the component type of newType.

  • System.arraycopy(original, 0, copy, 0,Math.min(original.length, newLength)): The System.arraycopy() method is used to copy the elements of the original array to a new array. Its parameters include the original array, the starting position of the original array (0 means starting from the first element), the target array (that is, the new array), the starting position of the target array (0 means starting from the first position), and the number of elements to copy, determined by the smaller of the original array length and newLength.

Example:

public static void main(String[] args) {

    String[] strArray = new String[]{"xj1","xj2","xj3","xj4","xj5"};
    String[] strArrayCopy = Arrays.copyOf(strArray,8);

    //向下转型
    TestEntity[] testArray = new TestChildEntity[]{new TestChildEntity("xiuji","xj")} ;
    TestChildEntity[] testChildArrayCopy =Arrays.copyOf(testArray,3,TestChildEntity[].class);

    System.out.println(Arrays.toString(strArrayCopy));
    System.out.println(Arrays.toString(testChildArrayCopy));

}

operation result:

[xj1, xj2, xj3, xj4, xj5, null, null, null]
[TestChildEntity{nickName='xj'name='xiuji'}, null, null]

Arrays.copyOfRange()

grammar:

No type conversion

copyOfRange(U[] original, int from, int toe) 

conversion type

copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) 
  • original: This is the original array whose elements are to be copied.
  • from: This is the starting index of the range to be copied.
  • to: This is the ending index (exclusive) of the range to be copied.
  • newType: This is the type of the new array, usually an array class.

Source code:

public static <T,U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) {
    int newLength = to - from;
    if (newLength < 0)
        throw new IllegalArgumentException(from + " > " + to);
    @SuppressWarnings("unchecked")
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, from, copy, 0,
                     Math.min(original.length - from, newLength));
    return copy;
}
  • int newLength = to - from;: This line calculates the length of the new array, based on the specified from and to indices.

  • if (newLength < 0) throw new IllegalArgumentException(from + " > " + to);: This line checks whether newLength is negative (i.e. whether from is greater than to). If this condition is met, it will throw an IllegalArgumentException indicating that the from index is greater than the to index.

  • @SuppressWarnings("unchecked"): This annotation is used to suppress unchecked type conversion warnings.

  • T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength);:
    This line creates a new array based on the specified newType. It uses reflection to create an array of the required type.
    If newType is equal to Object[].class, a new Object array is created with a length of newLength.
    Otherwise, it uses Array.newInstance to create a new array whose component type is the same as newType's component type and whose length is newLength. This enables you to create arrays of specific types.

  • System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength));:
    This line uses System.arraycopy to perform the actual array copy operation. It copies elements starting from the from index of the original array to the 0 index of the copy array. The number of elements to copy is determined by Math.min(original.length - from, newLength), ensuring that only the specified range is copied.

Example:

public static void main(String[] args) {

    String[] strArray = new String[]{"xj1","xj2","xj3","xj4","xj5"};
    String[] strArrayCopy = Arrays.copyOfRange(strArray,2,4);

    //向下转型
    TestEntity[] testArray = new TestChildEntity[]{new TestChildEntity("xiuji","xj")} ;
    TestChildEntity[] testChildArrayCopy =Arrays.copyOfRange(testArray,0,1,TestChildEntity[].class);

    System.out.println(Arrays.toString(strArrayCopy));
    System.out.println(Arrays.toString(testChildArrayCopy));

}

operation result:

[xj3, xj4]
[TestChildEntity{nickName='xj'name='xiuji'}]

Precautions

When using array copy, you need to pay attention to the following points:

  • If the length of the new array is less than the length of the source array, the new array will truncate the first few elements of the source array.

  • If the elements in the source array were object references, the elements in the new array will still reference the same objects, which means that modifications to the new array may affect the source array.

  • If the source array contains basic data types (such as int, char, etc.), the new array will contain the default values ​​of these basic data types, such as 0 or '\0' .

Summarize

When working with arrays, choosing the appropriate copy method depends on your specific needs. Here are some suggestions for using these methods:

  • If you need efficient low-level copy operations and the ability to manually calculate the starting position and number of elements, System.arraycopy may be a good choice.
  • Arrays.copyOf is a convenient option if you want to create a new array with the same length as the source array and copy the entire contents of the source array into the new array.
  • If you need to copy part of the source array to a new array, Arrays.copyOfRange is best suited.

Whichever method you choose, you'll ensure more flexibility, efficiency, and safety when working with arrays. Hopefully this article will help you better understand and use these array copy methods.

Guess you like

Origin blog.csdn.net/weixin_44002151/article/details/132789577