2010-04-07 118 views
59

ArrayList中的toArray方法,Bloch使用System.arraycopy和Arrays.copyOf来复制数组。什么更有效率:System.arraycopy vs Arrays.copyOf?

public <T> T[] toArray(T[] a) { 
    if (a.length < size) 
     // Make a new array of a's runtime type, but my contents: 
     return (T[]) Arrays.copyOf(elementData, size, a.getClass()); 
    System.arraycopy(elementData, 0, a, 0, size); 
    if (a.length > size) 
     a[size] = null; 
    return a; 
} 

如何比较这两种复制方式,何时使用哪种?

+1

什么是 “布洛赫”?为什么代码片段相关? – 2015-05-02 13:56:23

+2

@Ciro Bloch是编写ArrayList实现的人。 – Insomniac 2015-06-04 23:33:14

+0

另请参见:https://stackoverflow.com/q/44487304/14955 – Thilo 2017-06-12 03:14:39

回答

86

区别在于Arrays.copyOf不仅复制元素,它还创建一个新的数组。 System.arrayCopy复制到现有阵列中。

以下是Arrays.copyOf的来源,因为您可以看到它在内部使用System.arraycopy来填充新阵列。

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { 
    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; 
} 
+1

它显而易见.... Arrays.copyOf应创建一个新的实例因为我们没有传递给它;而我们将目标传递给System.arraycopy。关于速度,显然System.arraycopy应该赢得,因为它是一个本地方法,并最终Arrays.copyOf也调用这个方法来复制一个数组。 – 2016-07-24 14:58:42

+2

Java源代码[无所谓](https://stackoverflow.com/questions/44487304/why-arrays-copyof-is-2-times-faster-than-system-arraycopy-for-small-arrays#comment75970318_44487304 ),因为内在是创建的。 – maaartinus 2017-06-11 20:10:02

11

System.arrayCopy要快得多。它在系统中,因为它使用Java land之外的直接内存拷贝。尽可能使用它。

+1

但System.arraycopy只复制到现有数组中。 Arrays.copyOf也为你创建输出数组。 – Thilo 2010-04-07 03:24:56

+2

这是真的,只要你在封面下使用System.arraycopy,你使用的任何便利包装只是肉汁。 – 2010-04-07 13:28:51

+4

而且,有些情况下'System.arrayCopy' *不能*使用直接内存拷贝。 – 2011-11-22 09:29:02

3

System.arrayCopy本地实现,因此将比任何Java代码更快。我建议你使用它。

+4

仅仅因为它通过JNI使用本地代码,并不意味着它会更快:http://www.javaspecialists.eu/archive/Issue124.html – Dag 2012-11-27 17:26:54

31

虽然System.arraycopy是本地实现的,因此可能会比一个Java循环快,它并不总是一样快,你可能期望。考虑下面这个例子:

Object[] foo = new Object[]{...}; 
String[] bar = new String[foo.length]; 

System.arraycopy(foo, 0, bar, 0, bar.length); 

在这种情况下,foobar阵列的基本类型有不同的基本类型,所以arraycopy的实现必须检查复制每一个引用的类型,以确保它实际上是对String实例的引用。这比数组内容的简单C风格memcopy慢得多。

的另一点是,Arrays.copyOf使用System.arraycopy引擎盖下,所以节省您创建一个新的阵列,通过arraycopy将微乎其微自己加油吧实现。假设这就是你想要做的...

我的建议是使用的版本,使您的代码最容易阅读,只担心哪一个更快,如果分析告诉你,它很重要。


1 - 它可能更快,但它是也可以的JIT编译器优化手工代码回路是没有区别的这么好的工作。

+1

+1用于指出有时需要进行的类型检查。 – Thilo 2010-04-07 06:43:31

+0

@StephenC,关于你的第一段,是否有情况下'System.arrayCopy'实际上可能*较慢*? – Pacerier 2014-08-18 02:50:01

+0

@Prier - 我不知道任何。但这不是不可能的。 – 2014-08-18 05:28:09

12

如果你想要一个数组的精确复印件(比方说,如果你想要做一个防守副本),复制数组的最有效的办法可能是使用数组对象的clone()方法:

class C { 
    private int[] arr; 
    public C(int[] values){ 
     this.arr = values.clone(); 
    } 
} 

我并没有打算测试它的性能,但它是一个非常快的机会,因为它都是本机的(调用中分配和复制),而克隆是一种特殊的JVM祝福的复制对象的方式(其他用途主要是邪恶的),并且可能会采取一些“捷径”。

就个人而言,如果它比任何其他复制方式都慢,我仍然会使用clone,因为它更容易阅读,几乎不可能在写入时搞砸。 System.arrayCopy,另一方面...

+1

对,但'System.arrayCopy'也是原生的(它专用于该任务),而'clone'似乎必须处理很多*条件* ... – Pacerier 2014-08-18 02:55:28

+0

@Pacerier“我不经常使用'克隆“......但是当我这样做时,我在阵列上使用它。” – gustafc 2014-08-18 07:16:44

+0

我在谈论* * .clone()'当在数组上使用时....无论如何,它仍然会返回一个Object,然后它必须被转换回数组(=额外的工作)。 – Pacerier 2014-08-18 07:27:50

10

你看过Sun的Arrays.copyOf()的实现吗?

public static int[] copyOf(int[] original, int newLength) { 
    int[] copy = new int[newLength]; 
    System.arraycopy(original, 0, copy, 0, 
        Math.min(original.length, newLength)); 
    return copy; 
} 

可以看出,它采用System.arraycopy()内部,这样的表现是相同的。

0
 class ArrayCopyDemo { 
    public static void main(String[] args) { 
    char[] copyFrom = { 'd', 'e', 'c', 'a', 'f', 'f', 'e', 
      'i', 'n', 'a', 't', 'e', 'd' }; 
    char[] copyTo = new char[7]; 

    System.arraycopy(copyFrom, 2, copyTo, 0, 7); 
    System.out.println(new String(copyTo)); 
} 
} 
0

而不是辩论,这些是实际结果。显然,您的选择取决于您想要复制多少数据。

字节[]复制性能试验

10,000,000迭代40B array.copyOfRange:135ms systems.arraycopy:141ms

10,000,000迭代1000B array.copyOfRange:1861ms systems.arraycopy:2211ms

10,000,000迭代4000b array.copyOfRange:6315ms systems.arraycopy:5251ms

百万迭代10万桶 array.copyOfRange:15,198ms systems.arraycopy:14783ms

相关问题