【问题标题】:Why does Java not have block-scoped variable declarations?为什么 Java 没有块范围的变量声明?
【发布时间】:2008-09-26 18:28:59
【问题描述】:

以下方法不起作用,因为内部块声明了一个与外部块中的变量同名的变量。显然变量属于声明它们的方法或类,而不是声明它们的块,因此我不能编写一个简短的小临时块用于调试,碰巧将外部范围内的变量推入阴影只是片刻:

void methodName() {
  int i = 7;
  for (int j = 0; j < 10; j++) {
    int i = j * 2;
  }
}

我用过的几乎所有块范围语言都支持这一点,包括我在学校编写的解释器和编译器的琐碎小语言。 Perl 可以做到这一点,Scheme 也可以,甚至 C 也可以。甚至 PL/SQL 也支持!

这个 Java 设计决策的基本原理是什么?

编辑:正如有人指出的那样,Java 确实有块作用域。我要问的概念的名称是什么?我希望我能从那些语言设计课程中记住更多。 :)

【问题讨论】:

    标签: java syntax language-design


    【解决方案1】:

    嗯,严格来说,Java确实有块范围的变量声明;所以这是一个错误:

    void methodName() {
      for (int j = 0; j < 10; j++) {
        int i = j * 2;
      }
      System.out.println(i); // error
    }
    

    因为 'i' 在 for 块之外不存在。

    问题在于 Java 不允许您创建与在同一方法的外部块中声明的另一个变量具有相同名称的变量。正如其他人所说,据说这样做是为了防止难以识别的错误。

    【讨论】:

      【解决方案2】:

      因为作者经常故意这样做,然后因为忘记现在有两个同名的变量而完全搞砸了。他们更改了内部变量名称,但保留了使用该变量的代码,现在无意中使用了先前隐藏的变量。这导致程序仍然可以编译,但执行错误。

      同样,意外隐藏变量并改变程序行为的情况并不少见。在不知不觉中隐藏现有变量可以像我上面提到的取消隐藏变量一样轻松地更改程序。

      允许这种阴影几乎没有什么好处,以至于他们将其排除在外,因为它太危险了。说真的,只需将新变量命名为其他变量,问题就会消失。

      【讨论】:

      • 我会进一步说没有理由这样做。没有影子变量,您无能为力。
      • 我喜欢它们的一次是在构造函数参数中,所以我可以执行“this.foo = foo”。为了构造函数而修改名称是丑陋的,丑陋的,丑陋的。 “foo”,“foo”,等等。
      【解决方案3】:

      我认为原因是大多数时候,这不是故意的,而是编程或逻辑缺陷。

      在像您这样微不足道的示例中,这是显而易见的,但在一大段代码中,意外地重新声明变量可能并不明显。

      ETA:它也可能与 java 中的异常处理有关。我认为这个问题的一部分是在一个与为什么在 try 部分中声明的变量在 catch/finally 范围中不可用有关的问题中讨论的。

      【讨论】:

      • 我第一次看到这个是在异常处理中。在那里我什么都没想。我只是假设由于某种内部原因,实现排除了它。直到我注意到它影响了普通方块,我才真正开始思考“为什么”?
      【解决方案4】:

      我猜它会导致难以发现的错误。在 C# 中类似。

      Pascal 不支持这一点,因为您必须在函数体上方声明变量。

      【讨论】:

        【解决方案5】:

        这个问题的基本假设是错误的。

        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++;
        }
        

        我一生都无法弄清楚为什么您希望范围界定以任何其他方式表现。无法确定您在 for 循环中指的是哪个 i,我敢打赌,您有 99.999% 的机会想要在方法中引用 i

        【讨论】:

        • 我确实想参考方法内部的 i 。这就是 C、Perl 和 Scheme 的工作方式。那么为什么这使我无法确定我想要哪个呢?
        【解决方案6】:

        另一个原因:如果允许这种变量声明,人们会想要(需要?)一种访问外部块变量的方法。可能会添加“外部”关键字:

        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;
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-09-10
          • 2012-06-11
          • 2016-10-21
          • 1970-01-01
          • 1970-01-01
          • 2012-08-27
          相关资源
          最近更新 更多