Java 效率更高的是:System.arraycopy还是Arrays.copyOf?

Java 效率更高的是:System.arraycopy还是Arrays.copyOf?,java,arrays,performance,Java,Arrays,Performance,在ArrayList中的toArray方法中,Bloch使用System.arraycopy和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

ArrayList
中的
toArray
方法中,Bloch使用
System.arraycopy
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;
}
public T[]toArray(T[]a){
如果(a.长度<尺寸)
//创建a的运行时类型的新数组,但我的内容:
return(T[])array.copyOf(elementData,size,a.getClass());
System.arraycopy(elementData,0,a,0,size);
如果(a.长度>尺寸)
a[size]=null;
返回a;
}

如何比较这两种复制方法以及何时使用哪种方法?

System.arrayCopy速度更快。它之所以在系统中,是因为它使用Java land之外的直接内存拷贝。尽可能使用它。

是本机实现的,因此比任何Java代码都要快。我建议您使用它。

区别在于
数组。copyOf
不仅复制元素,还创建新数组<代码>系统。阵列复制复制到现有阵列中

以下是
数组.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;
}

<代码>公共静态t[]复制(U[]原始、int NethLoad、类< P>而<代码>系统。ARRAYPrime<代码>是本地实现的,因此可以比java循环快一点,但它并不总是像您预期的那么快。
Object[] foo = new Object[]{...};
String[] bar = new String[foo.length];

System.arraycopy(foo, 0, bar, 0, bar.length);
在这种情况下,
foo
bar
数组具有不同的基本类型,因此
arraycopy
的实现必须检查复制的每个引用的类型,以确保它实际上是对字符串实例的引用。这比数组内容的简单C样式
memcopy
要慢得多美国

另一点是
Arrays.copyOf
在引擎盖下使用
System.arraycopy
。因此
System.arraycopy
表面上的速度不应该比
Arrays.copyOf
慢2。但是您可以看到(从引用的代码中)在某些情况下,
array.copyOf
将使用反射来创建新的数组。因此性能比较并不简单

这种分析有几个缺陷

  • 我们正在查看Java特定版本的实现代码。这些方法可能会改变,从而使以前关于效率的假设失效

  • 我们忽略了JIT编译器可以对这些方法进行一些巧妙的特例优化的可能性。显然,这确实发生在
    数组中。copyOf
    ;请参阅。这种方法是“固有的”在当前一代Java实现中,这意味着JIT编译器将忽略Java源代码中的内容

  • 但无论哪种方式,这两个版本之间的差异都是
    O(1)
    (即独立于数组大小)且相对较小。因此,我的建议是使用使代码更易于阅读的版本,如果分析告诉您这很重要,只需担心哪一个更快


    1-它可能更快,但JIT编译器也可能在优化手动编码循环方面做得很好,没有什么区别。

    如果您想要一个数组的精确副本(比如,如果您想要做一个防御性副本),复制数组的最有效方法可能是使用数组对象的
    克隆()
    方法:

    class C {
        private int[] arr;
        public C(int[] values){
            this.arr = values.clone();
        }
    }
    
    我没有费心去测试它的性能,但它很有可能非常快,因为它都是本机的(在调用中分配和复制),而克隆是一种特殊的复制对象的方式(对于其他目的来说,它通常是有害的),并且可能会采取一些“捷径”


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

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


    可以看出,它在内部使用了
    System.arraycopy()
    ,因此性能将是相同的。

    这些是实际结果,而不是争论。显然,您的选择将取决于要复制的数据量

          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));
    }
     }
    
    字节[]复制性能测试

    10000000次迭代40b array.copyOfRange:135ms systems.arraycopy:141ms

    10000000次迭代1000b array.copyOfRange:1861ms systems.arraycopy:2211ms

    10000000次迭代4000b array.copyOfRange:6315ms systems.arraycopy:5251ms

    1000000次迭代1000000b array.copyOfRange:15198ms
    systems.arraycopy:14783ms

    如果您查看System.arraycopy()of和Array.copyOf()的源代码以了解性能

    System.arraycopy()是C代码,它直接在数组上运行,不返回任何值,因此它的运行速度应该比array.copyOf()快得多。尽管如此,如果您需要创建一个新数组,或者如果您只需要复制操作的值,那么您必须为此创建一个新数组,设置新数组长度等。因此,您无法执行返回System.arraycopy(源,0,目标,0,长度)

    对于Array.copyOf()可以做什么,它将为您创建一个新数组。您可以将Array.copyOf()的返回值分配给数组,或将其作为Array.copyOf()从方法返回返回给您一个值,而不是直接在目标数组上操作。因此,您的代码看起来会更干净。尽管如此,出于性能方面的考虑,array.copyOf()是一个泛型类型方法,它不知道将使用什么。因此,它必须调用array.newInstance()或new Object()然后将其转换为输入的数组类型


    总之,出于性能考虑,请使用System.arraycopy()。对于更干净的代码,请使用Array.copyOf()。

    我在另一个答案中发布了这一点,但在这里可能也很有用

    我知道这不是
          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));
    }
     }
    
     String[] a = new String[baseSize]; // f.e - 10.000.000
     int size = baseSize / 24;
     int rem = baseSize % 24;
    
     long start = System.currentTimeMillis();
     
     String[][]pieces = new String[23][size];
     String[] last = new String[size + rem];   
     for (int i = 0; i < 23; i++)
        System.arraycopy(a, (size * i), pieces[i], 0 , size); 
     System.arraycopy(a, (size * 23), last, 0 ,(size) + rem); 
    
     long elapsed = System.currentTimeMillis() - start;
    
     long start = System.currentTimeMillis();
    
     String[][] pieces = new String[23][];
     for (int i = 0; i < 23; i++)
        pieces[i] = Arrays.copyOfRange(a, size * i, size * (i + 1)); 
     String[] last = Arrays.copyOfRange(a, size * 23, (size * 24) + rem);
    
     long elapsed = System.currentTimeMillis() - start;