有什么理由比clone()更喜欢System.arraycopy()吗?
在复制整个数组时,我经常看到人们这样写:
int[] dest = new int[orig.length];
System.arraycopy(orig, 0, dest, 0, orig.length);
但在我看来,没有理由更喜欢这个:
int[] dest = orig.clone();
无论如何,它们都是浅拷贝。也许这些人只是没有意识到克隆的存在。那么有什么理由不使用clone
呢?
When copying an entire array, I've often seen people write:
int[] dest = new int[orig.length];
System.arraycopy(orig, 0, dest, 0, orig.length);
But it seems to me there is no reason to favor this over:
int[] dest = orig.clone();
They're both shallow copies anyway. Probably these folks just don't realize that clone
exists. So is there any reason not to use clone
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
clone()
使用其自己的引用创建第一个数组的不同副本。System.arraycopy()
使用JNI(Java Native Interface)进行复制一个数组(或它的一部分),所以它是
正如您可以确认的那样,速度极快
此处;
clone()
创建一个与旧数组具有相同特征的新数组,即相同大小、相同类型和相同内容。请参阅此处了解的一些示例>克隆
在行动;手动复制
就是手动复制。这个方法没什么好说的,只不过很多人发现它是最表现出色。arraynew = arrayold
不复制数组;它只是指向arraynew
到arrayold
的内存地址,或者换句话说,您只是分配一个引用到旧数组。clone()
makes a distinct copy of the first array with its own reference.System.arraycopy()
uses JNI (Java Native Interface) to copyan array (or parts of it), so it is
blazingly fast, as you can confirm
here;
clone()
creates a new array with the same characteristics as the old array, i.e., same size, same type, and same contents. Refer to here for some examples ofclone
in action;manual copying
is, well, manual copying. There isn't much to say about this method, except that many people have found it to be the most performant.arraynew = arrayold
doesn't copy the array; it just pointsarraynew
to the memory address ofarrayold
or, in other words, you are simply assigning a reference to the old array.不。如果您确实进行微基准测试,那么也许可以,具体取决于您运行的 JVM。但实际上,没有。
No. If you're really microbenchmarking, then maybe, depending on what JVM you're running. But in actuality, no.
我在思考同样的疑问时,恰巧看到了这个问题。我觉得 arraycopy() 是预定义数组时使用的方法(即内存已分配)。因此,不会重复与存储器分配相关的开销。
例如,想象一下您定义了一个定期更新的大型数组的情况。然后使用
clone()
将在每次复制数组时重新创建所需大小的数组。但是,arraycopy()
使用预先分配的内存空间。因此,与
clone()
相比,arraycopy()
在某些情况下更有效。另一方面,clone()
会产生紧凑的代码。I happened to look at this question when I was pondering on the same doubt. I feel that the
arraycopy()
is a method to be used when the array is predefined (i.e. memory is already allocated). Thus, the overhead associated with memory allocation is not repeated.For example, imagine a case when you have defined a large array which is updated periodically. Then using
clone()
will recreate a array of required size every time the array is copied. However,arraycopy()
uses the pre-allocated memory space.Thus
arraycopy()
is more efficient in certain scenarios compared toclone()
. On the other handclone()
results in a compact code.使用
System.arraycopy
或Arrays.copyOf
而不是clone()
使您的代码更加明确,因此更易于理解。它说“我正在复制一个数组”,而不是“我正在(神奇地)复制某种对象”。但支持
的主要论点Arrays.copyOf
方法(以及针对clone()
)是类型安全,缺乏这一点可能是clone() 最大的问题
这可能会导致微妙的错误,如果您不小心正在克隆的对象具有您想要的确切数组组件类型。让我们以 JDK-6260652 错误为例。罪魁祸首是在
Arrays.ArrayList
中使用clone()
来实现Collection.toArray()
(它被声明为返回Object []
)。这个特定的ArrayList
是java.util.Arrays
中的一个私有类,由Arrays.asList(T... a)
使用实例化a
作为其后备数组,而不关心a
的实际类型,它可能是String[]
或Integer[]
> (或者其他实际上不是的对象[]
)。其toArray()
方法返回a.clone()
的问题在于,程序员最终可能会使用Arrays.ArrayList.toArray()
> 在某些时候做这样的事情:这种错误可能会被忽视很多年,因为上面说明的使用模式并不常见。只要考虑一下集合框架自 JDK 1.2(1998 年)以来就已经存在,但这个特定问题直到 2005 年才被报告(10 年后有人发现了一个JDK 不同部分中的类似问题)。 JDK-6260652 补丁(在 Java 9 中发布)很简单将
a.clone()
替换为Arrays.copyOf(a, a.length,对象[].class)
。总而言之,我赞成使用数组复制方法而不是
clone()
的论点是:System.arraycopy
:Arrays.copyOf
:Using
System.arraycopy
orArrays.copyOf
instead ofclone()
makes your code more explicit and therefore easier to understand. It says "I'm copying an array" as opposed to "I'm (magically) copying some kind of object".But the main argument in favor of the
Arrays.copyOf
methods (and againstclone()
) is type-safety, the lack of which is probably the biggest gotcha ofclone()
that could lead to subtle bugs if you're not careful that the object you're cloning has the exact array component type that you want.Let's look at the JDK-6260652 bug for example. The culprit was
clone()
being used inArrays.ArrayList
to implementCollection.toArray()
(which is declared to returnObject[]
). This particularArrayList
is a private class injava.util.Arrays
instantiated byArrays.asList(T... a)
usinga
as its backing array without caring about the actual type ofa
, which might have been aString[]
orInteger[]
(or whatever else that's not actuallyObject[]
). The problem with itstoArray()
method returninga.clone()
here is that a programmer might end up usingArrays.ArrayList.toArray()
at some point to do something like this:This kind of bug can go unnoticed for years because the usage pattern illustrated above is not common. Just consider that the Collections framework has been around since JDK 1.2 (1998) but this particular issue wasn't reported until 2005 (and 10 years later someone discovered a similar issue in a different part of the JDK). The patch for JDK-6260652 (released in Java 9) simply replaces
a.clone()
withArrays.copyOf(a, a.length, Object[].class)
.To summarize, my arguments in favor of using the array copy methods instead of
clone()
are:System.arraycopy
:Arrays.copyOf
:这里只是猜测,但使用 System.arraycopy 可能是有充分理由的,因为不同的 JVM 可以通过利用底层系统的本机功能来提高性能的方式来实现它们。
例如,JVM 实现可以使用像 memcpy 这样的本机库调用,它可能会利用一些内存控制器技巧以某种令人难以置信的快速和巧妙的方式执行操作。但是,由于其虚拟性质,
Object.clone
实现可能不适合进行此类优化。Just guessing here, but there might be a good reason to use
System.arraycopy
because different JVM's could conceivably implement them in a way that takes advantage of native abilities of the underlying system for a performance boost.For example, a JVM implementation could use a native library call like
memcpy
which could potentially take advantage of some memory controller tricks to perform the action in some incredibly fast and clever way. However, theObject.clone
implementation might not be a good candidate for such optimization due to its virtual nature.