List接口提供了四种位置方法(索引) 访问列表元素。列表(如Java数组)基于零。注意 这些操作可以在与索引成比例的时间内执行 某些实现的值(例如LinkedList类)。 因此,迭代列表中的元素通常是优选的 如果调用者不知道实现,则通过它进行索引。
这是什么意思?这是否意味着我更喜欢
ListIterator<Integer> iterator = list.listIterator(0);
iterator.next()
iterator.next()
结束
list.get(1)
如果是这样,为什么?如果基础列表实现是普通数组,get
将在恒定时间内执行。但是使用迭代器O(n)
。我在这里缺少什么?
这是否意味着我应该使用list.listIterator(1);
代替list.get(1)
?
答案 0 :(得分:11)
没有。但你应该更喜欢
for (Integer value : list) {
// do something with value
}
(或显式使用列表&#39;迭代器的循环)
在
for (int i = 0; i < list.size(); i++) {
Integer value = list.get(i);
// do something with value
}
如果列表是链表,则第一个是O(N),而第二个是O(N ^ 2)。实际上,在每次迭代时,它需要遍历列表(从开始或结束,取决于i
的值),直到它到达i
位置。当您使用Iterator或foreach循环时,这不会发生。
另一个好的理由是,在并发列表的情况下,迭代器可以是一致的(即迭代在创建迭代器时创建的列表的一致快照)。对于使用列表索引的迭代,情况可能不是这样。
答案 1 :(得分:3)
我几乎肯定这意味着循环遍历列表中的所有元素,最好是迭代而不是,例如:
// possibly slow depending on List implementation used
for (int i = 0; i < list.size(); ++i)
{
Foo bar = list.get(i);
}
对于LinkedList
,其中随机访问不是O(1),每次调用list.get(i)
时,您都必须从一开始就一直迭代到i
这是不必要的。
您的纯随机访问的示例(而不是循环遍历所有内容)是:
在LinkedList
的情况下,更详细(但基本上是什么
get(i)
引人入胜)
如果是ArrayList
,实际上比get(i)
答案 2 :(得分:2)
Javadoc正在谈论的是这种情况:
for (int i = 0; i < list.size(); i++) {
Object o = list.get(i);
}
如果list
的实现是ArrayList
,那么你是正确的,对每个特定元素(整个列表的O(n)
)访问底层数组将是恒定的时间。但是,如果它是LinkedList
怎么办?要访问链接列表中的元素n
,您必须在到达元素[0, 1, ... n - 2, n - 1]
之前迭代n
。如果对数组中的每个元素执行此操作,现在效率非常低。
因此,更好的方法是使用迭代器编写for循环:
// uses the iterator under the hood.
for (Object o : list) {
}
在这种情况下,ArrayList
迭代器将沿着数组行走,因此与第一个for循环一样快,而对于LinkedList
,它会跟踪列表中的位置,因此您不必遍历整个列表以获得下一个元素。