java-四种数组拷贝方式分析

java-四种拷贝方式分析

    • 深拷贝
    • 浅拷贝
    • System.arraycopy
    • 为什么System.arraycopy执行的是浅拷贝,但二维数组的内存地址却不一样?
    • new和直接clone的区别?
    • Cloneable接口父类clone方法是否线程安全?
    • 如何测试一个源码方法是否线程安全?
    • 实现对象深拷贝的两种方式

近期在查阅jdk源码时发现,底层采用了大量System.arraycopy方法,同时查阅到java当中,常用的四种拷贝的方式,如下:

  • for
  • System.arraycopy
  • arrays.copyof
  • clone(实现Cloneable接口)
方式 深拷贝、浅拷贝 线程安全 执行效率
for 可自定义 可自定义 效率较低
clone 深拷贝 效率较高
System.arraycopy 浅拷贝 不安全 效率较高
arrays.copyof 浅拷贝(底层调用的System.arraycopy) 不安全 效率较高

深拷贝

在堆内存中分配新空间,将之前的数组堆内存中的内容拷贝到新的空间中。

详释:
对于深拷贝来说,不仅要复制对象的所有基本数据类型的成员变量值,还要为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象图进行拷贝。

浅拷贝

在堆内存中不会分配新的空间,而是增加一个引用变量和之前的引用指向相同的堆空间。

详释:
①对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,不会影响另一个对象拷贝得到的数据。
②对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。

System.arraycopy

public static native void arraycopy(
	Object src,  //源数组
	int  srcPos, //源数组的起始位置
    Object dest, //目标数组
    int destPos, //目标数组的起始位置
    int length   //复制长度
)

为什么System.arraycopy执行的是浅拷贝,但二维数组的内存地址却不一样?

String[][] str = {
                {"a1","b1","c1"},
                {"a2","b2","c2"},
                {"a3","b3","c3"}
        };
String[] newStr = new String[3];
System.arraycopy(str[0],0,newStr,0,str.length);

System.out.println(str[0][0] == newStr[0]);
System.out.println(str[0][1] == newStr[1]);
System.out.println(str[0][2] == newStr[2]);
System.out.println(str[0] == newStr);

效果:

true
true
true
false

new和直接clone的区别?

new操作符的本意是分配内存。程序执行到new操作符时, 首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部就可以使用这个引用操纵这个对象。

而clone在第一步是和new相似的, 都是分配内存,调用clone方法时,分配的内存和源对象(即调用clone方法的对象)相同,然后再使用原对象中对应的各个域,填充新对象的域, 填充完成之后,clone方法返回,一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部 。

Cloneable接口父类clone方法是否线程安全?

如何测试一个源码方法是否线程安全?

https://segmentfault.com/a/1190000009922279

实现对象深拷贝的两种方式

https://blog.csdn.net/ly823260355/article/details/84993995

参考资料
https://segmentfault.com/a/1190000009922279
https://www.cnblogs.com/dgwblog/p/9152358.html

学习Java的同学注意了!!!
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:543120397 我们一起学Java!

你可能感兴趣的:(java基础编程)