以下方法不起作用,因为内部块声明了与外部块中的名称相同的变量。显然,变量属于声明它们的方法或类,而不属于声明它们的块,因此我无法编写一个简短的临时块来进行调试,将外部作用域中的变量推送到阴影片刻:
void methodName() {
int i = 7;
for (int j = 0; j < 10; j++) {
int i = j * 2;
}
}
我曾经使用的几乎每一种块范围的语言都支持这种语言,包括我在学校编写解释器和编译器的琐碎小语言。 Perl可以做到这一点,就像Scheme一样,甚至是C.甚至PL / SQL都支持这个!
这个Java设计决策的基本原理是什么?
编辑:有人指出,Java确实有块范围。我问的概念的名称是什么?我希望我能从那些语言设计课程中记住更多。 :)
答案 0 :(得分:24)
严格来说,Java 确实具有块范围的变量声明;所以这是一个错误:
void methodName() {
for (int j = 0; j < 10; j++) {
int i = j * 2;
}
System.out.println(i); // error
}
因为'i'不在for块之外。
问题是Java不允许您创建一个与同一方法的外部块中声明的另一个变量同名的变量。正如其他人所说,据说这样做是为了防止难以识别的错误。
答案 1 :(得分:19)
因为作者有意这样做并且通过忘记现在有两个具有相同名称的变量而完全搞砸了,这种情况并不少见。它们更改内部变量名称,但保留使用变量的代码,现在无意中使用了以前隐藏的变量。这导致程序仍然编译,但执行缓慢。
同样,不小心隐藏变量并改变程序的行为并不罕见。在不知不觉中隐藏现有变量可以像在上面提到的那样轻松地改变程序。
允许这种阴影并没有太大的好处,他们认为它太危险了。说真的,只需将你的新变量称为别的东西,问题就会消失。
答案 2 :(得分:12)
我认为理由是大多数时候,这不是故意的,而是编程或逻辑缺陷。
在一个像你一样微不足道的例子中,它很明显,但是在一大块代码中,意外地重新声明一个变量可能并不明显。
ETA:它也可能与java中的异常处理有关。我认为这个问题的一部分是在一个问题中讨论的,该问题涉及为什么在try / section范围内没有在try部分中声明的变量。
答案 3 :(得分:10)
我猜,它会导致难以发现的错误。它与C#类似。
Pascal不支持这一点,因为你必须在函数体上面声明变量。
答案 4 :(得分:1)
这个问题的基本假设是错误的。
Java 确实具有块级范围。但它也有范围的层次结构,这就是为什么你可以在i
循环中引用for
,而不是在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++;
}
我不能为我的生活弄清楚为什么你想要确定范围以任何其他方式行事。在for循环中确定你指的是哪个i
是不可能的,我敢打赌你想在方法中引用i
的机会是99.999%。< / p>
答案 5 :(得分:0)
另一个原因:如果允许这种变量声明,人们会想要(需要?)一种访问外部块变量的方法。可能会添加类似“外部”关键字的内容:
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;
}
}
}