The following method does not work because the inner block declares a variable of the same name as one in the outer block. Apparently variables belong to the method or class in which they are declared, not to the block in which they are declared, so I therefore can't write a short little temporary block for debugging that happens to push a variable in the outer scope off into shadow just for a moment:
以下方法不起作用,因为内部块声明与外部块中的名称相同的变量。显然,变量属于声明它们的方法或类,而不属于声明它们的块,因此我无法编写一个简短的临时块来进行调试,这会将外部作用域中的变量推送到阴影片刻:
void methodName() {
int i = 7;
for (int j = 0; j < 10; j++) {
int i = j * 2;
}
}
Almost every block-scoped language I've ever used supported this, including trivial little languages that I wrote interpreters and compilers for in school. Perl can do this, as can Scheme, and even C. Even PL/SQL supports this!
几乎我用过的每一种块范围的语言都支持这种语言,包括我在学校编写解释器和编译器的琐碎小语言。 Perl可以做到这一点,就像Scheme一样,甚至是C.甚至PL / SQL都支持这个!
What's the rationale for this design decision for Java?
这个Java设计决策的基本原理是什么?
Edit: as somebody pointed out, Java does have block-scoping. What's the name for the concept I'm asking about? I wish I could remember more from those language-design classes. :)
编辑:有人指出,Java确实有块范围。我问的概念是什么名字?我希望我能从那些语言设计课程中记住更多。 :)
6 个解决方案
#1
12
I believe the rationale is that most of the time, that isn't intentional, it is a programming or logic flaw.
我认为理由是大部分时间,这不是故意的,它是一种编程或逻辑缺陷。
in an example as trivial as yours, its obvious, but in a large block of code, accidentally redeclaring a variable may not be obvious.
在一个像你一样微不足道的例子中,它显而易见,但是在一大块代码中,意外地重新声明一个变量可能并不明显。
ETA: it might also be related to exception handling in java. i thought part of this question was discussed in a question related to why variables declared in a try section were not available in the catch/finally scopes.
ETA:它也可能与java中的异常处理有关。我认为这个问题的一部分是在一个问题中讨论的,该问题涉及为什么在try / finally范围内没有在try部分中声明的变量。
#2
24
Well, strictly speaking, Java does have block-scoped variable declarations; so this is an error:
严格地说,Java确实具有块范围的变量声明;所以这是一个错误:
void methodName() {
for (int j = 0; j < 10; j++) {
int i = j * 2;
}
System.out.println(i); // error
}
Because 'i' doesn't exist outside the for block.
因为'i'不存在于for block之外。
The problem is that Java doesn't allow you to create a variable with the same name of another variable that was declared in an outer block of the same method. As other people have said, supposedly this was done to prevent bugs that are hard to identify.
问题是Java不允许您创建一个变量,该变量与在同一方法的外部块中声明的另一个变量的名称相同。正如其他人所说,据说这样做是为了防止难以辨认的错误。
#3
19
Because it's not uncommon for writers to do this intentionally and then totally screw it up by forgetting that there are now two variables with the same name. They change the inner variable name, but leave code that uses the variable, which now unintentially uses the previously-shadowed variable. This results in a program that still compiles, but executes buggily.
因为作者有意这样做并且通过忘记现在有两个具有相同名称的变量而完全搞砸了,这种情况并不少见。它们更改内部变量名称,但保留使用变量的代码,现在无意中使用了以前隐藏的变量。这导致程序仍然编译,但执行缓慢。
Similarly, it's not uncommon to accidentally shadow variables and change the program's behavior. Unknowingly shadowing an existing variable can change the program as easily as unshadowing a variable as I mentioned above.
同样,不小心隐藏变量并改变程序的行为并不罕见。在不知不觉中遮蔽现有变量可以像在上面提到的那样轻松地改变程序。
There's so little benefit to allowing this shadowing that they ruled it out as too dangerous. Seriously, just call your new variable something else and the problem goes away.
允许这种阴影并没有太大的好处,他们认为它太危险了。说真的,只需将你的新变量称为别的东西,问题就会消失。
#4
10
It leads to bugs that are hard to spot, I guess. It's similar in C#.
我猜,这会导致难以发现的错误。它与C#类似。
Pascal does not support this, since you have to declare variables above the function body.
Pascal不支持这一点,因为你必须在函数体上面声明变量。
#5
1
The underlying assumption in this question is wrong.
这个问题的基本假设是错误的。
Java does have block-level scope. But it also has a hierarchy of scope, which is why you can reference i
within the for
loop, but not j
outside of the for loop.
Java确实具有块级范围。但它也有一个范围的层次结构,这就是为什么你可以在for循环中引用i,但不能在for循环之外引用j。
public void methodName() {
int i = 7;
for (int j = 0; j < 10; j++) {
i = j * 2;
}
//this would cause a compilation error!
j++;
}
I can't for the life of me figure out why you would want scoping to behave any other way. It'd be impossible to determine which i
you were referring to inside the for loop, and I'd bet chances are 99.999% of the time you want to refer to the i
inside the method.
我不能为我的生活弄清楚为什么你会希望确定范围以任何其他方式行事。在for循环中确定你指的是哪一个是不可能的,并且我敢打赌你想在方法中引用i的机会是99.999%。
#6
0
another reason: if this kind of variable declaration were allowed, people would want (need?) a way to access outer block variables. may be something like "outer" keyword would be added:
另一个原因:如果允许这种变量声明,人们会想要(需要?)一种方法来访问外部块变量。可能会添加“outer”关键字:
void methodName() {
int i = 7;
for (int j = 0; j < 10; j++) {
int i = outer.i * 2;
if(i > 10) {
int i = outer.outer.i * 2 + outer.i;
}
}
}
#1
12
I believe the rationale is that most of the time, that isn't intentional, it is a programming or logic flaw.
我认为理由是大部分时间,这不是故意的,它是一种编程或逻辑缺陷。
in an example as trivial as yours, its obvious, but in a large block of code, accidentally redeclaring a variable may not be obvious.
在一个像你一样微不足道的例子中,它显而易见,但是在一大块代码中,意外地重新声明一个变量可能并不明显。
ETA: it might also be related to exception handling in java. i thought part of this question was discussed in a question related to why variables declared in a try section were not available in the catch/finally scopes.
ETA:它也可能与java中的异常处理有关。我认为这个问题的一部分是在一个问题中讨论的,该问题涉及为什么在try / finally范围内没有在try部分中声明的变量。
#2
24
Well, strictly speaking, Java does have block-scoped variable declarations; so this is an error:
严格地说,Java确实具有块范围的变量声明;所以这是一个错误:
void methodName() {
for (int j = 0; j < 10; j++) {
int i = j * 2;
}
System.out.println(i); // error
}
Because 'i' doesn't exist outside the for block.
因为'i'不存在于for block之外。
The problem is that Java doesn't allow you to create a variable with the same name of another variable that was declared in an outer block of the same method. As other people have said, supposedly this was done to prevent bugs that are hard to identify.
问题是Java不允许您创建一个变量,该变量与在同一方法的外部块中声明的另一个变量的名称相同。正如其他人所说,据说这样做是为了防止难以辨认的错误。
#3
19
Because it's not uncommon for writers to do this intentionally and then totally screw it up by forgetting that there are now two variables with the same name. They change the inner variable name, but leave code that uses the variable, which now unintentially uses the previously-shadowed variable. This results in a program that still compiles, but executes buggily.
因为作者有意这样做并且通过忘记现在有两个具有相同名称的变量而完全搞砸了,这种情况并不少见。它们更改内部变量名称,但保留使用变量的代码,现在无意中使用了以前隐藏的变量。这导致程序仍然编译,但执行缓慢。
Similarly, it's not uncommon to accidentally shadow variables and change the program's behavior. Unknowingly shadowing an existing variable can change the program as easily as unshadowing a variable as I mentioned above.
同样,不小心隐藏变量并改变程序的行为并不罕见。在不知不觉中遮蔽现有变量可以像在上面提到的那样轻松地改变程序。
There's so little benefit to allowing this shadowing that they ruled it out as too dangerous. Seriously, just call your new variable something else and the problem goes away.
允许这种阴影并没有太大的好处,他们认为它太危险了。说真的,只需将你的新变量称为别的东西,问题就会消失。
#4
10
It leads to bugs that are hard to spot, I guess. It's similar in C#.
我猜,这会导致难以发现的错误。它与C#类似。
Pascal does not support this, since you have to declare variables above the function body.
Pascal不支持这一点,因为你必须在函数体上面声明变量。
#5
1
The underlying assumption in this question is wrong.
这个问题的基本假设是错误的。
Java does have block-level scope. But it also has a hierarchy of scope, which is why you can reference i
within the for
loop, but not j
outside of the for loop.
Java确实具有块级范围。但它也有一个范围的层次结构,这就是为什么你可以在for循环中引用i,但不能在for循环之外引用j。
public void methodName() {
int i = 7;
for (int j = 0; j < 10; j++) {
i = j * 2;
}
//this would cause a compilation error!
j++;
}
I can't for the life of me figure out why you would want scoping to behave any other way. It'd be impossible to determine which i
you were referring to inside the for loop, and I'd bet chances are 99.999% of the time you want to refer to the i
inside the method.
我不能为我的生活弄清楚为什么你会希望确定范围以任何其他方式行事。在for循环中确定你指的是哪一个是不可能的,并且我敢打赌你想在方法中引用i的机会是99.999%。
#6
0
another reason: if this kind of variable declaration were allowed, people would want (need?) a way to access outer block variables. may be something like "outer" keyword would be added:
另一个原因:如果允许这种变量声明,人们会想要(需要?)一种方法来访问外部块变量。可能会添加“outer”关键字:
void methodName() {
int i = 7;
for (int j = 0; j < 10; j++) {
int i = outer.i * 2;
if(i > 10) {
int i = outer.outer.i * 2 + outer.i;
}
}
}