Java高级篇-6-数组拷贝方法

来源:互联网 发布:杀人软件 编辑:程序博客网 时间:2024/05/29 18:23
       前面我们介绍了Array和Arrays类几个常用的方法,没有提到对象clone()方法和Arrays.copyOf(),关于拷贝,放到这篇来讨论。拷贝或者复制,一般是对象的引用的操作,有三种方式来实现:直接赋值,浅拷贝,深拷贝。下面我们用代码来理解这三种情况。面试中经常拿数组的几种拷贝方法,来考察你对浅拷贝和深拷贝的理解。特别是直接赋值和对象clone这两个方法。

1.直接赋值

       直接赋值很简单,例如Int a = 10, 第二行b=a,这里直接把a赋值给了b。这个时候,a和b是相等,内存地址相同,值也相等。我们用一个int基本类型的数组来举例。

package demo3;import java.lang.reflect.Array;import java.util.Arrays;/** * create by Anthony on 2017/10/29 */public class ArraysDemo {    public static void main(String args[]){        int[] a = {40, 20, 50, 10, 60, 30};        int[] b = a;                System.out.println(a == b);        //证明a发生变化,b会不会也变化        Array.set(a,2,100);        System.out.println("a "+Arrays.toString(a));        System.out.println("b "+Arrays.toString(b));    }}

运行结果:

truea [40, 20, 100, 10, 60, 30]b [40, 20, 100, 10, 60, 30]
       从运行结果看出:数组a和数组b确实是完全相等,值相等,内存地址也相同。也就是说数组a和数组b实际上都是指向了同一个对象。上面修改了数组a的值,直接赋值得到的数组b的值也跟随变化。

2.浅拷贝

      上面直接赋值的结果就是数组a和数组b完全相同,如果修改a,b也会跟着修改。实际上,我们可能不希望这样,我们希望复制过来的b和a进行区分,两者保持独立,不能互相影响。实现这个功能有一个方法就是Object的clone()方法。Object是Java的对象,所有类的父类。这个克隆实现的功能是:创建一个新对象,然后将当前对象的非静态字段复制到该新对象,如果字段是值类型的,那么对该字段执行复制;如果该字段是引用类型的话,则复制引用但不复制引用的对象。因此,原始对象及其副本引用同一个对象。

2.1 我们先看看如果字段是值类型,也就是八大基本数据类型的情况

package demo3;import java.lang.reflect.Array;import java.util.Arrays;/** * create by Anthony on 2017/10/29 */public class ArraysDemo {    public static void main(String args[]){        int[] a = {40, 20, 50, 10, 60, 30};        int[] b = a.clone();        System.out.println(a == b);        //证明a发生变化,b会不会也变化        Array.set(a,2,100);        System.out.println("a "+Arrays.toString(a));        System.out.println("b "+Arrays.toString(b));    }}

运行结果:

falsea [40, 20, 100, 10, 60, 30]b [40, 20, 50, 10, 60, 30]
      上面可以看出,数组a是Int类型,也就是一个基本数据类型的数组,所以直接进行了值的复制。复制之后,数组b和数组a是内存地址不相等。如果我们操作数组a,数组b是不会受到影响。

2.2 看看如果是引用型的数组

package demo3;import java.lang.reflect.Array;import java.util.Arrays;/** * create by Anthony on 2017/10/29 */public class ArraysDemo {    public static void main(String args[]){        String[] a = {"Beijing", "ShangHai", "HeBei", "GuangZhou", "XiAn"};        String[] b = a.clone();        System.out.println(a == b);        //证明a发生变化,b会不会也变化        Array.set(a,2,"WuHan");        System.out.println("a "+Arrays.toString(a));        System.out.println("b "+Arrays.toString(b));    }}

运行结果:

falsea [Beijing, ShangHai, WuHan, GuangZhou, XiAn]b [Beijing, ShangHai, HeBei, GuangZhou, XiAn]

       上面我们数组变成了String类型,里面的元素值也是String,我们知道String是一个类,不属于基本数据类型,所以,这里是引用类型。因为数组索引为2的元素是一个String类型,数组a和数组b的索引为2的元素都指向同一个索引,当修改a中引用指向的值是WuHan,数组b由于引用没有发生改变,所以值也没有跟着变化,还是指向了HeBei。clone()比较特殊,对于对象而言,它是深拷贝,但是对于数组而言,它是浅拷贝,因为数组每个元素如果是引用类型的话,数组本来存储的就是对象的引用。

2.3 System.arrayCopy()实现浅拷贝

package demo3;import java.lang.reflect.Array;import java.util.Arrays;/** * create by Anthony on 2017/10/29 */public class ArraysDemo {    public static void main(String args[]){        String[] a = {"Beijing", "ShangHai", "HeBei", "GuangZhou", "XiAn"};        String[] b = new String[a.length];        System.arraycopy(a, 0, b, 0, a.length);        System.out.println(a == b);        //证明a发生变化,b会不会也变化        Array.set(a,2,"WuHan");        System.out.println("a "+Arrays.toString(a));        System.out.println("b "+Arrays.toString(b));    }}

2.4 Arrays.copyOf()实现浅拷贝

package demo3;import java.lang.reflect.Array;import java.util.Arrays;/** * create by Anthony on 2017/10/29 */public class ArraysDemo {    public static void main(String args[]){        String[] a = {"Beijing", "ShangHai", "HeBei", "GuangZhou", "XiAn"};        String[] b = Arrays.copyOf(a, a.length);        System.out.println(a == b);        //证明a发生变化,b会不会也变化        Array.set(a,2,"WuHan");        System.out.println("a "+Arrays.toString(a));        System.out.println("b "+Arrays.toString(b));    }}

        关于浅拷贝,推荐2.3或者2.4的方法,2.3执行速度更快。我分别测试了下,System.arraycopy显示0毫秒,而Arrays.copyOf()输出1毫秒。其实Arrays.copyOf()内部实现是调用了System.arraycopy方法。

3.深拷贝

       深拷贝,就是说创建一个新对象,然后将当前对象的非静态字段复制到该新对象,无论该字段是值类型的还是引用类型,都进行复制。由于数组元素本来就存储对象的引用,所以,这里无法举例来实现数组的深拷贝。以后在类和对象的知识来介绍对象的深拷贝。