如果javac按照我的想法行事,以下几行将产生相同的效果:
for (Object o: getObjects()) {}
List<Object> os = getObjects(); for (Object o: os) {}
是这样吗?或者它可能是特定于实现的?如果是这样:有人知道GWT吗?
答案 0 :(得分:7)
表现将完全相同。
Java编译器通过调用循环对象上的Iterator
方法,将每个循环转换为围绕iterator()
对象的循环。
因此,实际列表实例仅使用一次。 (致电iterator()
)
答案 1 :(得分:7)
来自Java语言规范:
14.14.2 The enhanced for statement
增强的for语句有 形式:
EnhancedForStatement: for ( VariableModifiersopt Type Identifier: Expression) Statement
Expression必须具有类型
Iterable
或者它必须是 数组类型(第10.1节),或编译时 发生错误。声明的局部变量的范围 在FormalParameter中的一部分 增强的
for
声明(§14.14)是 包含的声明增强型
for
的含义 声明是通过翻译给出的 一个基本的for
陈述。如果
Expression
的类型是aIterable
的子类型,然后让I
成为 表达式的类型 表达。iterator()
。增强的for
语句是等效的 到...的基本for
陈述 形式:for (I #i = Expression.iterator(); #i.hasNext(); ) { VariableModifiersopt Type Identifier = #i.next(); Statement }
#i
是编译器生成的 与任何不同的标识符 其他标识符(编译器生成的 或者在其他方面)在范围内(§6.3) 在增强的点 声明发生。
如您所见, Expression
仅在for循环表达式的第一部分中提及,因此仅评估一次。所以你的两条线会产生相同的性能。
答案 2 :(得分:5)
从纯Java角度来看,这些答案似乎都是正确的。此外,如果可以,GWT编译器实际上将进一步重写增强的for循环,在生成JavaScript之前进入常规for循环。所以它实际上最终会看起来像:
for (int i = 0; i < getObjects().size(); i++) {
Object o = getObjects().get(i);
// ...
}
原因?如果从未引用List iterator对象,则可以将其声明为死代码,并且不会在JavaScript中重写,从而导致较小的下载大小。这种优化应该对代码的实际执行没有任何影响。
请参阅今年的Google I / O中的Optimizing apps with the GWT compiler,了解GWT编译器为减少JS大小而做的其他疯狂事情的更多细节。
答案 3 :(得分:3)
从实际角度来看,您可以检查两个字节码并进行比较:
m1()V
L0
ALOAD 0
INVOKEVIRTUAL it/funge/Console.getObjects()Ljava/util/List;
INVOKEINTERFACE java/util/List.iterator()Ljava/util/Iterator;
ASTORE 2
GOTO L1
L2
FRAME FULL [it/funge/Console T java/util/Iterator] []
ALOAD 2
INVOKEINTERFACE java/util/Iterator.next()Ljava/lang/Object;
ASTORE 1
L1
FRAME SAME
ALOAD 2
INVOKEINTERFACE java/util/Iterator.hasNext()Z
IFNE L2
L3
RETURN
m2()V
L0
ALOAD 0
INVOKEVIRTUAL it/funge/Console.getObjects()Ljava/util/List;
ASTORE 1
L1
ALOAD 1
INVOKEINTERFACE java/util/List.iterator()Ljava/util/Iterator;
ASTORE 3
GOTO L2
L3
FRAME FULL [it/funge/Console java/util/List T java/util/Iterator] []
ALOAD 3
INVOKEINTERFACE java/util/Iterator.next()Ljava/lang/Object;
ASTORE 2
L2
FRAME SAME
ALOAD 3
INVOKEINTERFACE java/util/Iterator.hasNext()Z
IFNE L3
L4
RETURN
它们是相同的,唯一的区别是你的第二个片段有两个独立的部分来加载List
然后获得迭代器。这也将消耗更多类的本地人,事实上它还有ALOAD
和ASTORE
以上,它用于通过两行代码存储getObjects
结果它直接使用它的片段..
答案 4 :(得分:2)
没有区别。 foreach构造只从对象中获取Iterator
。这就是为什么它必须实现Iterable
接口。