在for循环声明中初始化变量的范围实际上不仅仅是块范围吗?

考虑带有计数器的for循环:

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

一切都很好。 我们说i有“阻止”范围。

但是,为什么在i++中无法访问在for循环中声明的变量?

例如,为什么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-loop声明范围”? 如果是这样,我对如何在Java或C#等规范中定义此范围以及程序员通常所称的范围感兴趣。

编辑:是的,我知道我可以声明循环for (int j, i = 0; i < 100; i += j) ,但这仍然表明for循环声明的范围比它们的花括号更高。

JLS 6.3指明范围界定的面部原因:

在for语句(第14.14.1节)的ForInit部分中声明的局部变量的范围包括以下所有内容:

  • 它自己的初始化程序
  • for语句的ForInit部分右侧的任何其他声明符
  • for语句的Expression和ForUpdate部分
  • 包含的声明

身体的“包含声明”。 for body中定义的变量没有特殊的范围规则。 正常规则适用。 (它们也在JLS 6.3中。)


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

  • 如果你不得不在循环体内查看那里声明的变量2 ,那么可读性就不好了。
  • 确定循环中声明的变量是否明确初始化的逻辑很难指定,并且程序员很难理解。 例:

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

1 – 真正的原因只能在20世纪70年代为C的设计者所知。 我怀疑Java设计者是否认为它与C不同。他们试图使Java“像C一样”。

2 – 循环体中的某些东西可以修改循环变量,这已经够糟糕了。 🙁

第一个Scope以void main {}开头,而不是像你的for循环范围之后的其他内部块一样,并且使用第一个块声明的所有变量对于范围的所有内部块都是可见的, 我们必须在使用之前声明变量 (在您的情况下)变量j)你在for循环中使用了变量而没有声明它,因此在声明之前不可能使用它并且我们的光标到达for循环由于从上到下逐行逼近首先它是否声明了check变量?

一个非常有趣的问题。 如果从运行时透视图中查看j,则会提出一个非常好的观点,即在迭代后调用increment表达式时j应该是可见的。

但是从编译器的角度来看,当它读取for循环语句即(int i = 0; i < 100; i += j) ,它会期望j已经被声明。

我猜你可以说我有一个额外的声明范围,与i和j都有的块范围相比。

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

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

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