万隆的笔记 万隆的笔记
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
  • 笔试面试相关
  • Java复制数组的四种方法
    • 测试代码
    • 测试结果
    • for循环逐一复制
    • Arrays.copyOf
    • clone
    • System.arraycopy
    • 总结
  • interview_class_loader
  • 笔试面试题临时
  • interview
2022-04-16
目录

Java复制数组的四种方法

# Java复制数组的四种方法

Java复制数组有大概有四种复制方式,

  • for循环逐一复制
  • System.arraycopy
  • System.copyof
  • 使用clone方法

关于他们之间的执行效率,查阅网上相关资料,给出的结论是:

效率:System.arraycopy > clone > Arrays.copyOf > for循环

我自己编写测试代码进行实践,最后逐个分析。
这里会着重看一下clon方法,在面试中有可能会问到浅拷贝和深拷贝的问题。

# 测试代码

package indi.wwl.interview.example;

import java.util.Arrays;

import com.wwl.utils.CodeMonitor;

/**
 * 复制数组的四种方法效率对比
 * 
 * @author Wwl 
 */
public class ArrayCopyDemo {

	public static final int size = 10;

	public static void main(String[] args) {
		
		String[] strArr = new String[size];
		for(int i = 0; i < size; ++i) {
			strArr[i]="model";
		}

		long forCost = new CodeMonitor() {
			@Override
			public void runCode() {
				String[] destArr = new String[size];
				for (int x = 0; x < strArr.length; ++x) {
					destArr[x] = strArr[x];
				}
			}
		}.getCostimeNanosecond(1000);
		
		long arraysCopyCost = new CodeMonitor() {
			@Override
			public void runCode() {
				String[] destArr = Arrays.copyOf(strArr, strArr.length);
			}
		}.getCostimeNanosecond(1000);

		long cloneCost = new CodeMonitor() {
			@Override
			public void runCode() {
				String[] destArr = strArr.clone();
			}
		}.getCostimeNanosecond(1000);
		
		long systemCopyCost = new CodeMonitor() {
			@Override
			public void runCode() {
				String[] destArr = new String[size];
				System.arraycopy(strArr, 0, destArr, 0, strArr.length);
			}
		}.getCostimeNanosecond(1000);

		System.out.println("for cost " + forCost + " nanosecond");
		System.out.println("Arrays.copyOf cost " + arraysCopyCost + " nanosecond");
		System.out.println("clone cost " + cloneCost + " nanosecond");
		System.out.println("System.arraycopy cost " + systemCopyCost + " nanosecond");

	}

}

代码中CodeMonitors是自己编写的一个抽象类,帮助计算Code运行的时间。 getCostimeNanosecond(1000)是执行1000Code所花费的平均时间。 计算时间的过程很简单:

    long start = System.nanoTime();
    runCode();
    long end = System.nanoTime();

# 测试结果

size=10
size=10
size=100
size=100
size=1000
size=1000
size=10000
size=10000

除了上图的展示,还每个size情况进行了多次运行观察,发现:

  • 数组元素不多时,Arrays.copyOf方法执行耗时是最多的,for方法在1000纳秒的时间徘徊,clone 和 System.arraycopy 经常不相伯仲,但多数是System.arraycopy执行时间更短。
  • 数组元素一多,几种方法的效率对比就很明显。基本上如开头提到的: System.arraycopy > clone > Arrays.copyOf > for循环

# for循环逐一复制

for循环是我们常用的一种程序循环结构,它的特点是代码灵活,但是效率最低。 for的速度之所以最慢我认为可能是因为下标表示法每次都从起点开始寻位到指定下标处(现代编译器应该对其有进行优化,改为指针),另外就是它每一次循环都要判断一次是否达到数组最大长度以及进行一次额外的记录下标值的加法运算。

# Arrays.copyOf

源码:

	@SuppressWarnings("unchecked")
	public static <T> T[] copyOf(T[] original, int newLength) {
		return (T[]) copyOf(original, newLength, original.getClass());
	}

	public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        @SuppressWarnings("unchecked")
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

查看Arrays.copyOf的源码可以发现,它实际上调用的就是System.arraycopy,效率肯定比System.arraycopy低。再加上很大一部分开销花在了Math.min函数上,所以效率就更低了。从代码可以看出来这是个浅拷贝。

# clone

源码:

	protected native Object clone() throws CloneNotSupportedException;

从源码上看到clone()是native方法,底层是用C语言实现的,返回类型为Object类型,在赋值的时候会发生强转,牺牲了一些效率。

clone()比较特殊,创建并返回对象的副本,可以进行浅拷贝和深拷贝。“复制”的精确含义可能取决于对象的类。关于克隆对象的相关知识,这里不展开讨论,更多详见深拷贝和浅拷贝。

# System.arraycopy

源码:

	/**
	* @param      src      the source array.
	* @param      srcPos   starting position in the source array.
	* @param      dest     the destination array.
	* @param      destPos  starting position in the destination data.
	* @param      length   the number of array elements to be copied.
	*/
	public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

从源码可以看到System.arraycopy()是也是native方法,底层用c或者c++实现的,因而速度会比较快。它是浅拷贝,对于非基本类型而言,它拷贝的是对象的引用,而不是去新建一个新的对象。

# 总结

在理想情况下,数组元素很多的时候,通常

效率:System.arraycopy > clone > Arrays.copyOf > for循环

上次更新: 5/31/2023, 1:14:42 AM
interview_class_loader

interview_class_loader→

最近更新
01
2025
01-15
02
Elasticsearch面试题
07-17
03
Elasticsearch进阶
07-16
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式