一维数组的四种拷贝方式

目录

  • 前言
  • 深拷贝与浅拷贝
  • 方式一:System.arraycopy()
    • 数组元素为基本类型
      • 内存分析
    • 数组元素为引用类型
      • 内存分析
  • 方式二:clone()方法
    • 数组元素为基本类型
      • 内存分析
    • 数组元素为引用类型
      • 内存分析
  • 方式三:Arrays.copyOf()方法
  • 方式四: for循环
    • 数组元素为基本类型
      • 内存分析
    • 数组元素为引用类型
      • 内存分析
  • 参考

前言

本文大部分内容出自:

笔者对相关内容进行了整理和补充。

深拷贝与浅拷贝

  • 浅拷贝:仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅拷贝出来的对象也会相应的改变。
  • 深拷贝:在计算机中开辟一块新的内存地址用于存放拷贝的对象。


因此,深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用。

方式一:System.arraycopy()

效率最高。

进入System类,发现arraycopy()是一个本地方法:

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

数组元素为基本类型

import java.util.Arrays;
public class TestDemo {public static void main(String[] args) {int[] array1 = new int[]{1,2,8,7,6};int[] array2 = new int[array1.length];System.arraycopy(array1, 0, array2, 0, array1.length);System.out.println("array1 = " + Arrays.toString(array1));System.out.println("array2 = " + Arrays.toString(array2));System.out.println("=========================");array2[0] = 100;System.out.println("array1 = " + Arrays.toString(array1));System.out.println("array2 = " + Arrays.toString(array2));}
}

输出结果:

        array1 = [1, 2, 8, 7, 6]array2 = [1, 2, 8, 7, 6]=========================array1 = [1, 2, 8, 7, 6]array2 = [100, 2, 8, 7, 6]

由结果可以看出,当对复制数组的某个元素进行改变时,并不影响被复制数组对应元素,即对于基本数据类型来说System.arraycopy() 方法是深拷贝。

内存分析

数组元素为引用类型

class TestArray{private int val = 10;public void setVal(int val){this.val = val;}public int getVal(){return this.val;}
}public class TestDemo {/**数组输出方法 */public static void printArray(TestArray[] array){for(int i = 0;i < array.length;i++){System.out.print(array[i].getVal()+" ");}System.out.println();}public static void main(String[] args) {TestArray[] array1 = new TestArray[3];// 数组引用赋值for (int i = 0; i < array1.length; i++){array1[i] = new TestArray();}TestArray[] array2 = new TestArray[array1.length];// 数组System.arraycopy()方法复制System.arraycopy(array1,0,array2,0,array1.length);printArray(array1);printArray(array2);System.out.println("==========");array2[0].setVal(100);;printArray(array1);printArray(array2);}
}

输出结果:

        10 10 10 10 10 10 ==========100 10 10 100 10 10

由结果可以看出,当对复制数组的某个元素进行改变时,被复制数组对应元素也随之改变,即对于引用数据类型来说 System.arraycopy() 方法是浅拷贝。

内存分析

方式二:clone()方法

效率次高。

数组元素为基本类型

import java.util.Arrays;
public class TestDemo {public static void main(String[] args) {int[] array1 = new int[]{1, 2, 8, 7, 6};int[] array2 = new int[array1.length];array2 = array1.clone();System.out.println("array1 = " + Arrays.toString(array1));System.out.println("array2 = " + Arrays.toString(array2));System.out.println("======================");array2[0] = 100;System.out.println("array1 = " + Arrays.toString(array1));System.out.println("array2 = " + Arrays.toString(array2));}
}

输出结果:

    array1 = [1, 2, 8, 7, 6]array2 = [1, 2, 8, 7, 6]======================array1 = [1, 2, 8, 7, 6]array2 = [100, 2, 8, 7, 6]

由结果可以看出,当对复制数组的某个元素进行改变时,并不影响被复制数组对应元素,即对于基本数据类型来说clone()方法实现数组拷贝也属于深拷贝。

截取上面程序的一小段,稍加改变:

    int[] array1 = new int[]{1, 2, 8, 7, 6};int[] array2 = new int[array1.length];System.out.println("array1 的地址是: " + array1);System.out.println("array2 的地址是: " + array2);array2 = array1.clone();System.out.println("array2 的地址是: " + array2);

输出结果:

    array1 的地址是: [I@7852e922array2 的地址是: [I@4e25154farray2 的地址是: [I@70dea4e

可以看到,刚开始通过int[] array2 = new int[array1.length]语句申请的数组和array2 = array1.clone()语句产生的数组并不是同一个数组。

通过查看clone()方法的源码,对于clone()方法的介绍,总纲是

Creates and returns a copy of this object.
创建并返回此对象的副本。

这就可以理解为什么array2数组克隆前后指向不同的地址了。

内存分析

数组元素为引用类型

class TestArray{private int val = 10;public void setVal(int val){this.val = val;}public int getVal(){return this.val;}
}public class TestDemo {/**数组输出方法 */public static void printArray(TestArray[] array){for(int i = 0;i < array.length;i++){System.out.print(array[i].getVal()+" ");}System.out.println();}public static void main(String[] args) {TestArray[] array1 = new TestArray[3];// 数组引用赋值for (int i = 0; i < array1.length; i++){array1[i] = new TestArray();}TestArray[] array2 = new TestArray[array1.length];// 数组clone()方法复制array2 = array1.clone();printArray(array1);printArray(array2);System.out.println("==========");array2[0].setVal(100);;printArray(array1);printArray(array2);}
}

输出结果:

        10 10 10 10 10 10 ==========100 10 10 100 10 10 

由结果可以看出,当对复制数组的某个元素进行改变时,被复制数组对应元素也随之改变,即对于引用数据类型来说clone()方法是浅拷贝。

内存分析

方式三:Arrays.copyOf()方法

进入Arrays类,发现其copyOf()方法的底层调用的是System.arraycopy()方法,因此该处将不再赘述其底层原理。

    public static int[] copyOf(int[] original, int newLength) {int[] copy = new int[newLength];System.arraycopy(original, 0, copy, 0,Math.min(original.length, newLength));return copy;}

该法的效率为第三高。

方式四: for循环

效率最低。

数组元素为基本类型

import java.util.Arrays;
public class TestDemo {public static void main(String[] args) {int[] array1 = new int[]{1, 2, 8, 7, 6};int[] array2 = new int[array1.length];for (int i = 0;i < array1.length;i++){array2[i] = array1[i];}System.out.println("array1 = " + Arrays.toString(array1));System.out.println("array2 = " + Arrays.toString(array2));System.out.println("======================");array2[0] = 100;System.out.println("array1 = " + Arrays.toString(array1));System.out.println("array2 = " + Arrays.toString(array2));}
}

输出结果:

array1 = [1, 2, 8, 7, 6]
array2 = [1, 2, 8, 7, 6]
======================
array1 = [1, 2, 8, 7, 6]
array2 = [100, 2, 8, 7, 6]

由结果可以看出,当对复制数组的某个元素进行改变时,并不影响被复制数组对应元素,即对于基本数据类型来说for循环语句是深拷贝。

内存分析

数组元素为引用类型

class TestArray{private int val = 10;public void setVal(int val){this.val = val;}public int getVal(){return this.val;}
}public class TestDemo {/**数组输出方法 */public static void printArray(TestArray[] array){for(int i = 0;i < array.length;i++){System.out.print(array[i].getVal()+" ");}System.out.println();}public static void main(String[] args) {TestArray[] array1 = new TestArray[3];// 数组引用赋值for (int i = 0; i < array1.length; i++){array1[i] = new TestArray();}TestArray[] array2 = new TestArray[array1.length];// 数组for循环复制for (int i = 0; i < array2.length; i++){array2[i] = array1[i];}printArray(array1);printArray(array2);System.out.println("==========");array2[0].setVal(100);;printArray(array1);printArray(array2);}
}

输出结果:

10 10 10 
10 10 10 
==========
100 10 10 
100 10 10

由结果可以看出,当对复制数组的某个元素进行改变时,被复制数组对应元素也随之改变,即对于引用数据类型来说for循环语句是浅拷贝。

内存分析

参考

[1].html
[2]
[3]
[4]
[5]