Java数组复制操作几种方式的性能分析

本文对比了System.arraycopy()、clone()、Arrays.copyOf()及for循环四种数组拷贝方法的性能,通过理论分析与实践测试,揭示了不同方法的效率差异及其背后原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

System.arraycopy() > clone() > Arrays.copyof() > for()

理论分析

前三种的复制方式都是相似的他们都是属于浅拷贝(基础类型的数据拷贝值,引用类型的数据拷贝引用),后面的用的是深拷贝,对于引用类型的数据来说相当于是直接建造了一个一模一样的新房屋。

@HotSpotIntrinsicCandidate注解的作用:JDK的Object类源码中,被@HotSpotIntrinsicCandidate标注的方法,在HotSpot中都有一套高效的实现,该高效实现基于CPU指令,运行时,HotSpot维护的高效实现会替代JDK的源码实现,从而获得更高的效率。

System.arraycopy()  是本地方法,也就是说是用C++写的,所以其效率比非native方法更高。它有@HotSpotIntrinsicCandidate注解,这个注解可以帮助他跳过JNI阶段进一步提高他的执行效率。这也是System.arraycopy()速度冠绝群雄的原因。

Object.clone()也是native方法,也有@HotSpotIntrinsicCandidate注解,但是从他的源码注解中可以看到It indicates that an annotated method may be (but is not guaranteed to be) intrinsified by the HotSpot VM它并没有被手工写在JVM里面,所以它不得不走JNI的路子,所以它就成了2哥。

Arrays.copyof():而且可以很明显的看到里面本质是调用了大哥  System.arraycopy()来实现的,并且他也不是本地方法,按理说他的效率是这三个最低的。

性能测试代码

    @Test
    public void test3(){
        //伪造数据数组的长度
        final int ArrayLength = 5000000;
        final int count = 50;
        Long[][] baseCostArrays = new Long[count][4];
        Long[][] refCostArrays = new Long[count][4];
        for (int i = 0; i < count; i++) {
            baseCostArrays[i] = testBaseCopy(ArrayLength,i);
            refCostArrays[i] = testRefCopy(ArrayLength,i);
        }
        //性能综合分析
        System.out.println("数组数据类型long、String两种,长度为:"+ArrayLength+",循环测试测试次数为:"+count);
        Long baseSystem = 0l;
        Long baseClone = 0l;
        Long baseArrays = 0l;
        Long baseFor = 0l;
        Long refSystem = 0l;
        Long refClone = 0l;
        Long refArrays = 0l;
        Long refFor = 0l;
        for (int i = 0; i <count; i++) {
            baseSystem = baseSystem+baseCostArrays[i][0];
            baseClone = baseClone+baseCostArrays[i][1];
            baseArrays = baseArrays+baseCostArrays[i][2];
            baseFor = baseFor+baseCostArrays[i][3];
            refSystem = refSystem+refCostArrays[i][0];
            refClone = refClone+refCostArrays[i][1];
            refArrays = refArrays+refCostArrays[i][2];
            refFor = refFor+refCostArrays[i][3];
        }
        System.out.println("~~~~~~~~~~~~~~数据性能分析~~~~~~~~~~~~~~~~~");
        System.out.println("基础类型数据:");
        System.out.println("System: _total:"+baseSystem+"  _average:"+(baseSystem*1.0/count));
        System.out.println("Clone: _total:"+baseClone+"  _average:"+(baseClone*1.0/count));
        System.out.println("Arrays: _total:"+baseArrays+"  _average:"+(baseArrays*1.0/count));
        System.out.println("For: _total:"+baseFor+"  _average:"+(baseFor*1.0/count));
        System.out.println("引用类型数据:");
        System.out.println("System: _total:"+refSystem+"  _average:"+(refSystem*1.0/count));
        System.out.println("Clone: _total:"+refClone+"  _average:"+(refClone*1.0/count));
        System.out.println("Arrays: _total:"+refArrays+"  _average:"+(refArrays*1.0/count));
        System.out.println("For: _total:"+refFor+"  _average:"+(refFor*1.0/count));

    }

    private Long[] testBaseCopy(int ArrayLength,int flag){
        System.out.println("~~进行的是基础类型数组的第"+(flag+1)+"次复制测验~~");
        Long costTimes[] = new Long[4];
        //测试System形式的拷贝
        float[] floats1 = new float[ArrayLength];
        for (int i = 0; i <ArrayLength; i++) {
            floats1[i] = 2342266L;
        }
        Long beginTime = new Date().getTime();
        float[] systemCopyArrays = new float[floats1.length];
        System.arraycopy(floats1,0,systemCopyArrays,0,floats1.length);
        costTimes[0]=performanceUtils("System.arraycopy",beginTime);
        //测试clone形式的拷贝
        float[] floats2 = new float[ArrayLength];
        for (int i = 0; i <ArrayLength; i++) {
            floats2[i] = 2362566L;
        }
        beginTime = new Date().getTime();
        float[] cloneCopyArrays = floats2.clone();
        costTimes[1]=performanceUtils("clone()",beginTime);
        //测试Arrays
        float[] floats3 = new float[ArrayLength];
        for (int i = 0; i <ArrayLength; i++) {
            floats3[i] = 2342546L;
        }
        beginTime = new Date().getTime();
        float[] arraysCopyArrays = Arrays.copyOf(floats3,floats3.length);
        costTimes[2]=performanceUtils("Arrays.copyOf",beginTime);
        //测试for
        float[] floats4 = new float[ArrayLength];
        for (int i = 0; i <ArrayLength; i++) {
            floats4[i] = 2343566L;
        }
        beginTime = new Date().getTime();
        float[] forCopyArrays = new float[floats4.length];
        for (int i = 0; i < forCopyArrays.length; i++) {
            forCopyArrays[i] = floats4[i];
        }
        costTimes[3]=performanceUtils("for",beginTime);
        return costTimes;
    }

    private Long[] testRefCopy(int ArrayLength,int flag){
        System.out.println("~~进行的是引用类型数组的"+(flag+1)+"复制测验~~");
        Long costTimes[] = new Long[4];
        Long beginTime = new Date().getTime();
        //测试System形式的拷贝
        String[] strings1 = new String[ArrayLength];
        for (int i = 0; i <ArrayLength; i++) {
            strings1[i] = new String("fasaadf");
        }
        beginTime = new Date().getTime();
        String [] systemCopyArrays = new String[strings1.length];
        System.arraycopy(strings1,0,systemCopyArrays,0,strings1.length);
        costTimes[0] = performanceUtils("System.arraycopy",beginTime);
        //测试clone形式的拷贝
        String[] strings2 = new String[ArrayLength];
        for (int i = 0; i <ArrayLength; i++) {
            strings2[i] = new String("fasddf");
        }
        beginTime = new Date().getTime();
        String[] cloneCopyArrays = strings2.clone();
        costTimes[1]=performanceUtils("clone()",beginTime);
        //测试Arrays
        String[] strings3 = new String[ArrayLength];
        for (int i = 0; i <ArrayLength; i++) {
            strings3[i] = new String("fassuiouoioidf");
        }
        beginTime = new Date().getTime();
        String[] arraysCopyArrays = Arrays.copyOf(strings3,strings3.length);
        costTimes[2]=performanceUtils("Arrays.copyOf",beginTime);
        //测试for
        String[] strings4 = new String[ArrayLength];
        for (int i = 0; i <ArrayLength; i++) {
            strings4[i] = new String("fasdfdf");
        }
        beginTime = new Date().getTime();
        String[] forCopyArrays = new String[strings4.length];
        for (int i = 0; i < forCopyArrays.length; i++) {
            forCopyArrays[i] = strings4[i];
        }
        costTimes[3]=performanceUtils("for",beginTime);
        return costTimes;
    }
    
    private Long performanceUtils(String Name,Long beginTime){
        Long duringTime = new Date().getTime()-beginTime;
        System.out.println(Name+"类型操作耗时:"+duringTime+"毫秒");
        return duringTime;
    }

 

 上面的测试结果我们可以看到他们之间的差别并不是有很大,并且Arrys的调用往往有更高的执行效率,对于这个问题我也比较疑问,不知道其中的原因,希望清楚的大佬可以留言指教一下。使用jdk15也是同样的执行效果

 

### Java 数组复制方式 Java 提供了多种方式来完成数组复制操作。以下是常见的五种方法及其具体实现: #### 1. 使用循环逐个赋值 通过手动遍历源数组并将每个元素逐一赋给目标数组,这是最基础的方法之一。 ```java public static void method01(int[] arr, int[] ans) { for (int i = 0; i < arr.length; i++) { ans[i] = arr[i]; } System.out.println("复制的ans数组为 " + Arrays.toString(ans)); } ``` 这种方法简单易懂,但在性能上可能不如其他内置方法高效[^1]。 #### 2. 使用 `Arrays.copyOf()` 方法 `Arrays.copyOf()` 是一种便捷的方式来创建一个新的数组并将其初始化为目标数组的内容。此方法支持指定新数组的长度,从而允许扩展或缩减数组大小。 ```java int[] original = {1, 2, 3, 4, 5}; int[] copy = Arrays.copyOf(original, original.length); System.out.println(Arrays.toString(copy)); ``` 该方法适用于快速复制整个数组或者调整其容量[^2]。 #### 3. 使用 `Arrays.copyOfRange()` 方法 如果只需要复制数组的一部分,则可以使用 `copyOfRange()` 来定义起始索引和结束索引之间的子集。 ```java int[] original = {1, 2, 3, 4, 5}; int[] subCopy = Arrays.copyOfRange(original, 1, 4); // 复制从索引1到索引3(不包括索引4) System.out.println(Arrays.toString(subCopy)); // 输出 [2, 3, 4] ``` 这种方式特别适合于处理部分数据的需求。 #### 4. 使用 `System.arraycopy()` 方法 `System.arraycopy()` 是一个底层高效的工具函数用于执行批量的数据移动。它可以直接控制源位置、目标位置以及复制的数量。 ```java int[] arr1 = {1, 2, 3, 4, 5}; int[] arr2 = new int[10]; System.arraycopy(arr1, 0, arr2, 0, arr1.length); System.out.println(Arrays.toString(arr2)); // 输出 [1, 2, 3, 4, 5, 0, 0, 0, 0, 0] ``` 相比简单的循环,这个方法通常更加快速且优化良好[^3]。 #### 5. 使用 `clone()` 方法 任何实现了 `Cloneable` 接口的对象都可以调用 `clone()` 方法生成一份浅拷贝副本。对于基本类型的数组来说,这同样是一个有效的选项。 ```java int[] original = {1, 2, 3, 4, 5}; int[] clonedArray = original.clone(); System.out.println(Arrays.toString(clonedArray)); ``` 需要注意的是,当涉及对象数组时,克隆仅会复制引用而不会深拷贝实际对象实例[^4]。 以上就是 Java 中常用的几种数组复制技术,每种都有各自的适用场景和特点。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值