编译器如何生成 Java 的 for 循环代码
编译器如何生成 Java 的 for 循环代码?
例如,如果我有:
for(String s : getStringArray() )
{
//do something with s
}
返回我要循环的数组的函数在哪里,函数是总是调用还是只调用一次?通常,使用此构造进行循环的代码有多最佳?getStringArray()
编译器如何生成 Java 的 for 循环代码?
例如,如果我有:
for(String s : getStringArray() )
{
//do something with s
}
返回我要循环的数组的函数在哪里,函数是总是调用还是只调用一次?通常,使用此构造进行循环的代码有多最佳?getStringArray()
for
以下是 Java 语言规范第 3 版的相关摘录,为清楚起见,稍作编辑:
JLS 14.14.2
语句的
增强增强语句的格式为:
for
for ( Type Identifier : Expression ) Statement
如果 的类型是数组类型,则增强型语句的含义由以下基本语句给出:
Expression
T[]
for
for
T[] a = Expression; for (int i = 0; i < a.length; i++) { Type Identifier = a[i]; Statement }
其中 和 是编译器生成的标识符,与在发生增强语句时作用域中的任何其他标识符(编译器生成的或以其他方式)不同。
a
i
for
因此,实际上该语言确实保证了它只会被评估一次。Expression
为了完整起见,以下是 is 类型时的等效性:Expression
Iterable
JLS 14.14.2
语句的
增强增强语句的格式为:
for
for ( Type Identifier : Expression ) Statement
如果 的类型是 的子类型,则设为表达式 的类型。增强语句等效于以下形式的基本语句:
Expression
Iterable
I
Expression.iterator()
for
for
for (I iter = Expression.iterator(); iter.hasNext(); ) { Type Identifier = iter.next(); Statement }
其中 是编译器生成的标识符,它与在发生增强语句时作用域中的任何其他标识符(编译器生成的或以其他方式)不同。
iter
for
请注意,如果既不是数组也不是数组,则这是编译时错误,因此上述两种情况是可以使用增强型循环的唯一情况。此外,为清楚起见,上面的引号省略了有关环上附加的任何标签和 附加在 上的任何修饰符的信息,但这些都按照人们的期望进行处理。Expression
Iterable
for
for
Identifier
for
以下是《有效的 Java 第 2 版》第 46 项中的一句话:比传统的 for 循环更喜欢 for-each 循环
在 1.5 版中引入的 for-each 循环通过完全隐藏迭代器或索引变量来消除混乱和出错的机会。生成的成语同样适用于集合和数组。请注意,使用 for-each 循环不会降低性能,即使对于数组也是如此。实际上,在某些情况下,与普通循环相比,它可能会提供轻微的性能优势,因为它只计算数组索引的限制一次。虽然你可以手动完成此操作,但程序员并不总是这样做。
for
因此,该书声称,实际上一些编译器超越了JLS转换,并对for-each循环执行额外的优化(当然,同时仍然保持其语义)。
总之,您不必担心 for-每个循环的性能。语言的规范是明智的(只评估一次),正是因为这是许多场景中的首选构造,编译器将确保尽可能地优化它们。Expression
JDK 1.4 引入了接口。它旨在为算法提供提示,对于给定的实现,迭代更有效:RandomAccess
List
for (int i = 0, n = list.size(); i < n; i++) {
list.get(i);
}
比
for (Iterator i = list.iterator(); i.hasNext(); ) {
i.next();
}
前循环是否考虑了这一点?还是它完全忽略了一个事实,即给定的可迭代实际上是一个列表?
应该注意的是,这意味着添加测试和向下转换将起作用,这将增加一个并不总是值得的开销,并且可以被认为是编译器语法糖功能的过早优化。(iterable instanceof List && iterable instanceof RandomAccess)
List