什么更有效:System.arraycopy或Arrays.copyOf?

2022-08-31 11:43:20

布洛赫 中的方法同时使用 和 来复制数组。toArrayArrayListSystem.arraycopyArrays.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

不同之处在于,它不仅复制元素,还会创建一个新数组。 复制到现有阵列中。Arrays.copyOfSystem.arraycopy

下面是 的源代码,如您所见,它在内部用于填充新数组:Arrays.copyOfSystem.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;
}

答案 2

虽然它是在本地实现的,因此可能比Java循环快1,但它并不总是像你想象的那么快。请考虑以下示例:System.arraycopy

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

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

在这种情况下,和 数组具有不同的基类型,因此 的实现必须检查复制的每个引用的类型,以确保它实际上是对 String 实例的引用。这比数组内容的简单C样式要慢得多。foobararraycopymemcopy

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

这种分析中存在一些缺陷。

  1. 我们正在研究来自特定版本的Java的实现代码。这些方法可能会改变,使以前关于效率的假设无效。

  2. 我们忽略了JIT编译器可以为这些方法进行一些聪明的特殊情况优化的可能性。显然,这确实发生在 ;请参阅为什么对于小型数组,Arrays.copyOf 比 System.arraycopy 快 2 倍?。此方法在当前一代 Java 实现中是“固有的”,这意味着 JIT 编译器将忽略 Java 源代码中的内容!Arrays.copyOf

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


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