本文大部分内容出自:https://s-ajie.blog.csdn.net/article/list/3
笔者对相关内容进行了整理和补充。
因此,深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用。
效率最高。
进入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() 方法是浅拷贝。
效率次高。
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@7852e922
array2 的地址是: [I@4e25154f
array2 的地址是: [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()
方法的底层调用的是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;
}
该法的效率为第三高。
效率最低。
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]https://www.cnblogs.com/mikeCao/p/8710837.html
[2]https://s-ajie.blog.csdn.net/article/details/79939248
[3]https://www.nowcoder.com/questionTerminal/e7c2d52c9cf0476bbba6aae6713dd303
[4]https://blog.csdn.net/qq_40178464/article/details/79941843
[5]https://s-ajie.blog.csdn.net/article/details/79942319