这是我的代码:
class HelloWorld {
char[] foo = {'a', 'b'};
// This will compile
void foo() {
for (char foo : foo) {
}
}
// This will not compile
void bar() {
for (char foo = 0; foo < foo.length; foo++) {
}
}
}
为什么foo
编译但编译bar
失败,并显示:
Error: char cannot be dereferenced
使 foo 中的循环编译但 bar 失败的两个循环声明之间有什么区别?
我们可以通过查看 JLS§14.14.2 对处理数组时增强for
如何工作的描述来了解差异:
增强的 for 语句等效于以下形式的基本 for 语句:
T[] #a = Expression; L1: L2: ... Lm: for (int #i = 0; #i < #a.length; #i++) { {VariableModifier} TargetType Identifier = #a[#i]; Statement }
请注意变量是如何在循环主体中声明的,而不是在循环的标头中声明的。也就是说,您的foo
函数如下所示:
void foo() {
{ // Freestanding block for scope, though not really needed as `foo` has
// nothing else in it
char[] a = foo; // T[] #a = Expression;
for (int i = 0; i < a.length; i++) {
char foo = a[i]; // {VariableModifier} TargetType Identifier = #a[#i];
}
}
}
这就是为什么你在增强for
中侥幸逃脱阴影,而不是在传统的for
中,它需要访问原始数组(获取其length
,获取i
的条目等)。
有关增强型for
循环的更多信息,请参阅Java "for each"循环如何工作?及其答案。
Java 语言规范对两个char foo
的作用域的定义不同:
在基本函数的ForInit部分中声明的局部变量的作用域
for
语句 (§14.14.1) 包括以下所有内容:
- 它自己的初始值设定项
for
声明的ForInit部分右侧的任何其他声明符for
语句的表达式和ForUpdate部分- 包含的声明
在FormalParameter部分中声明的局部变量的作用域 增强型
for
语句 (§14.14.2) 是包含的语句。
(JLS 8,第6.3节)
这完美地解释了您观察到的行为:本地foo
在基本for
循环的控制子句的范围内(在其声明右侧的任何位置),因此它在那里隐藏其他foo
,但在增强for
循环中,它的作用域只是循环语句 - 它不在循环控制子句的任何范围内。