在for循环声明中初始化的变量的范围实际上不仅限于块级作用域吗?

4
考虑一个带有计数器的for循环:
for (int i = 0; i < 100; i++ /* `i` is visible here */) {
    /* `i` is visible here */
}
/* `i` not visible here */

一切都好。我们说i具有“块级”作用域。

然而,为什么在for循环中声明的变量在i++时不可访问?

例如,为什么j在这里不在作用域内,即使它也具有“块级”作用域,并且是在i += j之前声明的?

for (int i = 0; i < 100; i += j /* only `i` is visible here */) {
    int j = 1;
    /* `i` and `j` are visible here */
}
/* `i` and `j` are not visible here */

我看到许多关于i范围的问题,但没有关于for循环括号内j范围的问题。这是否意味着实际上还有另一个范围,即“for循环声明范围”,但没有人谈论它?如果是这样,我对Java或C#等规范中如何定义此范围以及程序员通常称其为什么范围感兴趣。
编辑:是的,我理解我可以将循环声明为for (int j, i = 0; i < 100; i += j),但这仍然表明for循环声明的范围高于其花括号。
4个回答

4
这是因为JLS 6.3规定了如下范围:在基本的for语句(§14.14.1)的ForInit部分声明的局部变量的作用域包括以下所有内容:
- 它自己的初始化程序 - 在for语句的ForInit部分中向右进一步声明符号 - for语句的Expression和ForUpdate部分 - 包含的Statement
“包含的statement”是for循环体。对于在for循环体中定义的变量,没有特殊的作用域规则,适用普通规则(它们也在JLS 6.3中)。

这种语言设计背后的原因包括(我猜1)以下内容:

  • It would be bad for readability if you had to look inside the loop body for variables declared there2.
  • The logic to determine whether the variable declared in the loop was definitely initialized would be hard to specify, and difficult for programmers to understand. Example:

    for (i = 1; i < 10; i = i + j) {
        int j;
        if (i > 3) {
            j = 42;
        }
        // do stuff
    }
    

1- 真正的原因只有70年代C语言的设计者才知道。我怀疑Java的设计者并没有考虑与C不同的做法。他们试图让Java“类似于C”。

2- 循环体内的某些东西可能会修改循环变量,这已经够糟糕了。 :-(


0

第一个作用域以void main { }开头,然后是其他类似于您的for循环作用域的内部块,并且在此第一个块中声明的所有变量对作用域的所有内部块都可见。我们必须在使用变量之前声明它(在您的情况下是变量j),您在for循环中使用了未声明的变量,因此在声明之前无法使用它,由于自上而下逐行逼近的方式,当光标到达for循环时,首先检查变量是否已声明。


1
我的问题不是关于“什么”是可能的,而是关于这在文档和社区中是如何定义的。有很多时候编译器不会从上到下读取文件,例如,在读取类中的方法声明时,顺序并不重要。 - 4castle

0
非常有趣的问题。你提出了一个非常好的观点,即从运行时的角度来看,如果迭代后调用增量表达式,则 j 应该可见。
但是从编译器的角度来看,当它读取 for 循环语句,即 (int i = 0; i < 100; i += j),它会期望 j 已经被声明。
我想你可以说 i 比 i 和 j 都有额外的语句范围。

谢谢!“语句”作用域对我来说是新的。感觉编译器应该在尝试解析之前将i += j部分内部移动到for循环的末尾,但我想那不是它的工作方式。是否有关于“语句”作用域的规范或资源? - 4castle
看看Stephen的答案,那里有规格说明 :) - ritesh.garg

-1

变量J在声明/初始化之前被引用。当第一次循环执行时,JVM将没有对它的引用。

您已经在循环内部初始化了变量j。

我希望这能解决您的问题。


这并没有回答我的问题 :( - 4castle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接