详解Java数组的四种拷贝方式

 更新时间:2022年02月24日 08:21:59   作者:Emperor10  
Java数组一共有四种拷贝方式: for循环、copyof/copyOfRange、arraycopy和clone。本文将为大家详细介绍一下这四种方式,感兴趣的可以了解一下

深拷贝与浅拷贝的区别

假设现在有原数组A以及拷贝后的数组B,若是改变A中的某一个值,B数组随之相应的发生变化的拷贝方式称为浅拷贝,反之B数组不受影响,则称为深拷贝;
简单总结一下两者的概念:

深拷贝:拷贝后,修改原数组,不会影响到新数组;

浅拷贝:拷贝后,修改原数组,新数组也会相应的发生改变;

1. for循环进行拷贝

拷贝数值类型

当数组中存放的元素为基本数据类型时,此时发生的是深拷贝;

//1. for循环拷贝  (拷贝数值类型) ---深拷贝
    public static void main(String[] args) {
        int[] A = {1,2,3,4,5};
        int[] B = new int[A.length];
        for (int i = 0; i < A.length; i++) {
            B[i] = A[i];
        }
        System.out.println("A : " + Arrays.toString(A));  //A : [1, 2, 3, 4, 5]
        System.out.println("B : " + Arrays.toString(B));  //B : [1, 2, 3, 4, 5]
        System.out.println("===========修改后===========");
        A[0] = 100;
        System.out.println("A : " + Arrays.toString(A));  //A : [100, 2, 3, 4, 5]
        System.out.println("B : " + Arrays.toString(B));  //B : [1, 2, 3, 4, 5]
    }
    //打印对象数组的方法
    public static void show(Num[] arrays) {
        for (int i = 0; i < arrays.length; i++) {
            System.out.print(arrays[i].getVal() + " ");
        }
        System.out.println();
    }
class Num{
    public int val = 0;

    public Num(int val) {
        this.val = val;
    }

    public int getVal() {
        return val;
    }

    public void setVal(int val) {
        this.val = val;
    }
}

拷贝引用类型

当数组中存放的元素为引用数据类型时,此时发生的是浅拷贝;

//1. for循环拷贝  (拷贝引用数据类型) ---浅拷贝
    public static void main(String[] args) {
        Num[] A = new Num[4];
        A[0] = new Num(1);
        A[1] = new Num(2);
        A[2] = new Num(3);
        A[3] = new Num(4);
        Num[] B = new Num[4];
        for (int i = 0; i < A.length; i++) {
            B[i] = A[i];
        }
        show(A);  //1 2 3 4 
        show(B);  //1 2 3 4 
        System.out.println("===========修改后===========");
        A[0].setVal(100);
        show(A);  //100 2 3 4
        show(B);  //100 2 3 4
    }

2. copyof / copyOfRange

拷贝数值类型

当数组中存放的元素为基本数据类型时,此时发生的是深拷贝;

Arrays.copy(原数组,自定义新数组长度);

Arrays.copyOfRange(原数组,from,to);

注意拷贝截取的范围是左闭右开的[from,to)

//2. copy / copyOfRange  (拷贝数值类型) ---深拷贝
    public static void main(String[] args) {
        int[] A = {1,2,3,4,5};
        int[] B = Arrays.copyOf(A,A.length);
        int[] C = Arrays.copyOfRange(A,1,3);
        System.out.println("A : " + Arrays.toString(A));  //A : [1, 2, 3, 4, 5]
        System.out.println("B : " + Arrays.toString(B));  //B : [1, 2, 3, 4, 5]
        System.out.println("C : " + Arrays.toString(C));  //C : [2, 3]
        System.out.println("===========修改后===========");
        A[0] = 100;
        System.out.println("A : " + Arrays.toString(A));  //A : [100, 2, 3, 4, 5]
        System.out.println("B : " + Arrays.toString(B));  //B : [1, 2, 3, 4, 5]
        System.out.println("C : " + Arrays.toString(C));  //C : [2, 3]
    }

拷贝引用类型

当数组中存放的元素为类的对象时,此时发生的是浅拷贝;

//2. copy / copyOfRange  (拷贝引用类型) ---浅拷贝
    public static void main(String[] args) {
        Num[] A = new Num[4];
        A[0] = new Num(1);
        A[1] = new Num(2);
        A[2] = new Num(3);
        A[3] = new Num(4);
        Num[] B = Arrays.copyOf(A,A.length);
        show(A);  //1 2 3 4
        show(B);  //1 2 3 4
        System.out.println("===========修改后===========");
        A[0].setVal(100);
        show(A);  //100 2 3 4
        show(B);  //100 2 3 4
    }
class Num{
    public int val = 0;

    public Num(int val) {
        this.val = val;
    }

    public int getVal() {
        return val;
    }

    public void setVal(int val) {
        this.val = val;
    }
} 

3. arraycopy

拷贝数值类型

当数组中存放的元素为基本数据类型时,此时发生的是深拷贝;

System.arraycopy(src, srcPos dest, destPos, length);

其中各个参数分别表示 如下:

  • src :源数组
  • srcPos:源数组要复制的起始位置
  • dest:目标数组
  • destPos:目标数组复制的起始位置
  • length:复制的长度

所以srcPos和destPos都为0,且length为源数组长度时,表示完完整整的拷贝过来了;那么截取范围拷贝也举个例子,下面的代码中srcPos = 1,destPos = 2,length = 2,表示从A数组下标为1的位置开始截取2个元素,放到B数组中下标为2的位置作为起始位置,再对比一下输出看看。

//3. arraycopy  (拷贝数值类型) ---深拷贝
    public static void main(String[] args) {
        int[] A = {1,2,3,4,5};
        int[] B = new int[A.length];
        //System.arraycopy(A,0,B,0,A.length);
        System.arraycopy(A,1,B,2,2);
        System.out.println("A : " + Arrays.toString(A));  //A : [1, 2, 3, 4, 5]
        System.out.println("B : " + Arrays.toString(B));  //B : [0, 0, 2, 3, 0]
        System.out.println("===========修改后===========");
        A[0] = 100;
        System.out.println("A : " + Arrays.toString(A));  //A : [100, 2, 3, 4, 5]
        System.out.println("B : " + Arrays.toString(B));  //B : [0, 0, 2, 3, 0]
    }

拷贝引用类型

当数组中存放的元素为类的对象时,此时发生的是浅拷贝;

//3. arraycopy  (拷贝引用类型) ---浅拷贝
    public static void main(String[] args) {
        Num[] A = new Num[4];
        A[0] = new Num(1);
        A[1] = new Num(2);
        A[2] = new Num(3);
        A[3] = new Num(4);
        Num[] B = new Num[4];
        System.arraycopy(A,0,B,0,A.length);
        show(A);  //1 2 3 4
        show(B);  //1 2 3 4
        System.out.println("===========修改后===========");
        A[0].setVal(100);
        show(A);  //100 2 3 4
        show(B);  //100 2 3 4
    }
class Num{
    public int val = 0;

    public Num(int val) {
        this.val = val;
    }

    public int getVal() {
        return val;
    }

    public void setVal(int val) {
        this.val = val;
    }
} 

4. clone

拷贝数值类型

当数组中存放的元素为基本数据类型时,此时发生的是深拷贝;

//4. clone  (拷贝数值类型) ---深拷贝
    public static void main(String[] args) {
        int[] A = {1,2,3,4,5};
        int[] B = A.clone();
        System.out.println("A : " + Arrays.toString(A));  //A : [1, 2, 3, 4, 5]
        System.out.println("B : " + Arrays.toString(B));  //B : [1, 2, 3, 4, 5]
        System.out.println("===========修改后===========");
        A[0] = 100;
        System.out.println("A : " + Arrays.toString(A));  //A : [100, 2, 3, 4, 5]
        System.out.println("B : " + Arrays.toString(B));  //B : [1, 2, 3, 4, 5]
    }

拷贝引用类型

当数组中存放的元素为类的对象时,此时发生的是浅拷贝;

//4. clone  (拷贝引用类型) ---浅拷贝
    public static void main(String[] args) {
        Num[] A = new Num[4];
        A[0] = new Num(1);
        A[1] = new Num(2);
        A[2] = new Num(3);
        A[3] = new Num(4);
        Num[] B = A.clone();
        show(A);  //1 2 3 4
        show(B);  //1 2 3 4
        System.out.println("===========修改后===========");
        A[0].setVal(100);
        show(A);  //100 2 3 4
        show(B);  //100 2 3 4
    }

5. 总结

拷贝方式数值类型引用类型推荐使用
for循环深拷贝浅拷贝 
copyof深拷贝浅拷贝
arraycopy深拷贝浅拷贝
clone深拷贝浅拷贝 

由于arraycopy底层是C++写的,所以速度快,更多的是使用这个方法。

注意:本文中所有的引用数据类型都是以类的对象为例,使用的是对象数组,我们也知道引用类型包括类,接口,字符串等等。但是需要注意字符串是新的变量,所以如果是连个字符串数组进行拷贝,即使他们是引用类型,但是每次都会创建了一个字符串数组对象, 因此, 修改原数组, 不会影响到新数组,即深拷贝。

以上就是详解Java数组的四种拷贝方式的详细内容,更多关于Java数组拷贝的资料请关注脚本之家其它相关文章!

相关文章

  • 解析Java中如何获取Spring中配置的bean

    解析Java中如何获取Spring中配置的bean

    本篇文章是对在Java中如何获取Spring中配置的bean进行了详细的分析介绍,需要的朋友参考下
    2013-07-07
  • SpringBoot整合Scala构建Web服务的方法

    SpringBoot整合Scala构建Web服务的方法

    这篇文章主要介绍了SpringBoot整合Scala构建Web服务的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • Maven基础知识大梳理

    Maven基础知识大梳理

    这篇文章主要是Maven基础知识大梳理,Maven主要是用来解决导入java类依赖的jar,编译java项目主要问题,大家可以读一读这篇文章,更深一步的了解Maven
    2021-08-08
  • 解读Jvm的内存结构与GC及jvm参数调优

    解读Jvm的内存结构与GC及jvm参数调优

    这篇文章主要介绍了解读Jvm的内存结构与GC及jvm参数调优方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • Spring源码剖析之Spring处理循环依赖的问题

    Spring源码剖析之Spring处理循环依赖的问题

    大家都知道循环依赖依赖指的是Bean与Bean之间的依赖关系,循环依赖指的是两个或者多个Bean相互依赖,本文通过代码示例给大家讲解Spring处理循环依赖的问题,感兴趣的朋友一起看看吧
    2021-06-06
  • SpringBoot内存数据导出成Excel的实现方法

    SpringBoot内存数据导出成Excel的实现方法

    这篇文章主要给大家介绍了关于SpringBoot内存数据导出成Excel的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • 浅谈Java内存泄露

    浅谈Java内存泄露

    内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。下面我们来一起了解如何解决
    2019-05-05
  • Spring Boot虚拟线程Webflux在JWT验证和MySQL查询性能比较

    Spring Boot虚拟线程Webflux在JWT验证和MySQL查询性能比较

    这篇文章主要为大家介绍了Spring Boot虚拟线程与Webflux在JWT验证和MySQL查询上的性能比较,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • Gradle快速安装及入门

    Gradle快速安装及入门

    今天小编就为大家分享一篇关于Gradle快速安装及入门,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-10-10
  • Java连接Linux服务器过程分析(附代码)

    Java连接Linux服务器过程分析(附代码)

    这篇文章主要介绍了Java连接Linux服务器过程分析(附代码),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12

最新评论