如果将ArrayList引用为List,为什么ArrayList性能会有所不同?

时间:2013-06-11 11:18:37

标签: java time arraylist iteration random-access

kjellkod's article中提到,如果我们在接收ArrayList的方法中传递List作为参数,那么我们会失去性能,因为ArrayList实现了额外的RandomAccess接口。 文章示例:

// SLOWER: as shown in http://ideone.com/1wnF1
private static void linearInsertion(Integer[] intArray, List<Integer> list) {
[...]
int list_size = list.size();
for (int i = 0; i < list_size; i++) {
if (integer.compareTo(list.get(i)) >= 0) { // ... more code

// FASTER: as shown in http://ideone.com/JOJ05
private static void linearInsertion(Integer[] intArray, ArrayList<Integer> list) {
[...]
int list_size = list.size();
for (int i = 0; i < list_size; i++) {
if (integer.compareTo(list.get(i)) >= 0) { // ... more code

参考文献:

  

鼓励通用列表算法检查给定列表   是应用算法之前的此接口的实例   如果将其应用于顺序,则会提供较差的性能   访问列表,并在必要时改变其行为以保证   可接受的表现。

但是,如果我们真的在上面的方法中传递ArrayList并检查list instanceof RandomAccess,那么在两种情况下都是如此。 那么,我的第一个问题是为什么Java VM应该在第一种方法中将其解释为顺序列表?

我已修改了文章中的测试,以检查我的计算机上的此行为。当在ideone上运行测试时,它会显示类似于kjellkod的结果。但是当我在本地运行时,我得到了意想不到的结果,这与文章解释以及我的理解相反。似乎在我的情况下,ArrayList作为List迭代比将其作为ArrayList引用快5-25%:

enter image description here

如何解释这种差异?是否取决于架构或处理器核心数量?我的工作机配置是Windows 7 Professional x64,Intel Core i5-3470(4核,4线程),16 GB RAM。

2 个答案:

答案 0 :(得分:3)

  

那么,我的第一个问题是为什么Java VM应该在第一种方法中将其解释为顺序列表?

JVM没有顺序或随机访问列表的概念。 (除了标记接口)它是实现的开发者,它认识到ArrayList在O(1)时间而不是O(n)时间内执行随机访问查找。

  

是否取决于架构或处理器内核数量?

不,您会看到-client之间的差异,例如32位Windows和-server,例如任何64位JVM。


我怀疑你第二次运行List测试。这可能会更快,因为代码在JIT和CPU缓存中都会被警告。我建议你至少进行三次测试,先运行最长的测试,然后忽略你的第一次测试。

注意:对于List,contains()是O(n),这就是你的时间增长O(n ^ 2)的原因显然如果你想忽略重复并查看真正低效的行为,你就不会使用List代码可能会令人困惑,因为您很容易受到优化和不优化的微妙影响。通过比较已经合理优化的代码,您将获得更有意义的结果。

答案 1 :(得分:1)

尽管两种方法中的代码在理论上仍然相同,但可能存在差异,因为在JVM级别调用接口方法与调用类方法不同。它们是2种不同的字节码操作:invokeinterfaceinvokevirtual。见http://bobah.net/d4d/source-code/misc/invokevirtual-vs-invokeinterface-performance-benchmark