Java 在for循环声明中初始化的变量的范围实际上不仅仅是块范围吗?
考虑一个带计数器的Java 在for循环声明中初始化的变量的范围实际上不仅仅是块范围吗?,java,c#,for-loop,scope,language-agnostic,Java,C#,For Loop,Scope,Language Agnostic,考虑一个带计数器的for循环: for (int i = 0; i < 100; i++ /* `i` is visible here */) { /* `i` is visible here */ } /* `i` not visible here */ 我看到了许多关于I范围的问题,但在for循环括号中没有任何关于j范围的问题。这是否意味着在技术上还有另一个没有人谈论的范围,即“for循环声明范围”?如果是这样,我感兴趣的是在Java或C#等规范中如何定义这个范围,以及程序员
for
循环:
for (int i = 0; i < 100; i++ /* `i` is visible here */) {
/* `i` is visible here */
}
/* `i` not visible here */
我看到了许多关于I
范围的问题,但在for
循环括号中没有任何关于j
范围的问题。这是否意味着在技术上还有另一个没有人谈论的范围,即“for循环声明范围”?如果是这样,我感兴趣的是在Java或C#等规范中如何定义这个范围,以及程序员通常称之为什么范围
编辑:是的,我知道我可以将循环声明为
for(int j,I=0;I<100;I+=j)
,但这仍然表明for
循环声明的作用域比它们的花括号大。在声明/初始化之前引用变量j。当第一次执行循环时,JVM不会引用它
您已经在循环中初始化了变量j
我希望这能澄清你的问题。第一个作用域是以void main{}开始的,而不是像for循环作用域那样的其他内部块,并且用这个第一个块声明的所有变量对作用域的所有内部块都是可见的,我们必须在使用它之前声明变量(在你的例子中是变量j)您在for循环中使用了变量,但没有声明它,所以在声明和我们的游标到达for循环之前不可能使用它,因为从上到下的方法是逐行执行的,首先检查变量是否声明了 一个非常有趣的问题。您提出了一个非常好的观点,即当在迭代之后调用增量表达式时,如果从运行时的角度来看j,则j应该是可见的 但从编译器的角度来看,当它读取for循环语句时,即
(int i=0;i<100;i+=j)
,它希望j已经被声明
我想你可以说,与I和j都具有的块范围相比,我有一个额外的语句范围。这样指定范围的表面原因是: 在基本函数的ForInit部分声明的局部变量的范围 for声明(§14.14.1)包括以下所有内容:
- 它自己的初始值设定项
- for语句的ForInit部分右侧的任何其他声明符
- for语句的表达式和ForUpdate部分
- 所载声明
。对于主体的中定义的变量,没有特殊的作用域规则。正常规则适用。(它们也在JLS 6.3中。)
这种语言设计背后的原因包括(我猜1)以下几点:
- 如果必须查看循环体内部声明的变量2,则会对可读性造成不利影响
- 确定在循环中声明的变量是否确实初始化的逻辑很难指定,程序员也很难理解。例如:
for (i = 1; i < 10; i = i + j) {
int j;
if (i > 3) {
j = 42;
}
// do stuff
}
(i=1;i<10;i=i+j)的{
int j;
如果(i>3){
j=42;
}
//做事
}
1-真正的原因只有C。。。回到20世纪70年代。我怀疑Java设计者是否考虑过用不同于C的方式来实现它。他们试图使Java“类似C”
2-循环体中的某些内容可能会修改循环变量,这已经够糟糕的了-(这并没有回答我的问题:(Thank!“statement”作用域对我来说是新的。在试图解析它之前,编译器应该在内部将i+=j
部分移动到for
循环的末尾,但我想这不是它的工作方式。“statement”是否有任何规范或资源范围?看看Stephen对规范的回答:)我的问题不是关于“什么”是可能的,而是关于文档和社区在何处/如何定义它。有很多时候编译器不自上而下地读取文件,例如,在类中读取方法声明时,顺序并不重要。
for (i = 1; i < 10; i = i + j) {
int j;
if (i > 3) {
j = 42;
}
// do stuff
}