【问题标题】:Local variable in Java with the same name as a global variableJava中的局部变量与全局变量同名
【发布时间】:2016-04-06 14:56:59
【问题描述】:

我正在尝试了解 Java 中的范围。在 Perl 中,我可以执行以下操作:

my $x = 1;
{
    my $x = 2;
    say $x; # prints 2
}
say $x; # prints 1

换句话说,由于我在作用域内使用my 声明了变量 $x,因此该作用域中的 $x 变量是该作用域的本地变量(即,与全局 $x 变量不同的变量)。现在,在 Java 中我正在尝试做类似的事情,但我得到了错误

变量 rawURL 已在方法 run() 中定义

代码如下:

// Global rawURL
URI rawURl;
try {
  rawURL = new URI("http://www.google.com");
} catch (Exception e) {
  // Handle later
}

// Some time later
for (Element link : links) {
  // rawURL in this scope
  URI rawURL;
  try {
    rawURL = new URI(link.attr("abs:href"));
  } catch (Exception e) {
    // Handle later
  }
}

现在,问题是,我不想为我的所有变量名都发挥创意,确保每个变量名都不同。我只是使用 rawURL 来构建一个规范化的 URL,所以它本质上是一个临时变量。我可以这样做:

for (Element link : links) {
  rawURL = new URL(..);
}

但这会改变我的全局变量的内容,我真的不希望这样。有什么方法可以为局部变量使用与全局变量相同的名称?

【问题讨论】:

  • java中没有全局变量的概念。您可能需要为URI 重用或定义自己的新变量。
  • 如果你的方法太长以至于你的变量没有好名字,这强烈表明你的方法应该被拆分成更短的方法。每种方法都有自己的范围。顺便说一句,捕获异常也是非常糟糕的做法。
  • 我的方法没那么长。获取一个 URL,对其进行规范化,使用 jsoup 获取页面,解析 DOM,从页面中获取链接(规范化它们)并添加到 Redis。这就是它的全部内容,总共大约 40 行。
  • 是的,这就是你应该努力的方向。我也觉得你的问题是由你处理异常的方式引起的。您为什么不发布真实完整的代码,以便我们提出更好的替代方案。
  • ^您在这里很讽刺,但是是的,您的代码应该像您所描述的那样:Page page = getPageUsingJsoup(normalizeUrl(url)); for (Link link: getLinksFromPage(page)) { storeLinkInRedis(link); }。看,那是非常易读的代码,它不需要很多变量,它会按照你的描述做它应该做的事情。但我理解,对于 Perl 程序员来说,这么清晰可能看起来很可怕 :)

标签: java variables scope


【解决方案1】:

您必须使用新名称定义一个新的局部变量,因为变量的范围类似于:当前块 + 子块。因此,在您的情况下, rawURL 是为您所谓的“全局”定义的,并且它对子块可见,即在 for 块中。

在java中,你可以这样做:

{
   String myvar = "";
}

{
   String myvar = "";
}

因为这里,同一级别有两个不同的方块

但你不能这样做:

String myvar = "";
{
    String myvar = "";
}

因为同一块(子块)中的两个变量存在同名冲突。

【讨论】:

  • 这是不正确的。您当然可以在内部范围内定义具有相同名称的变量。它会警告你它会隐藏一个外部变量,但你仍然可以这样做,并且它的行为将与预期的一样(与 perl 中的方式相同)。
  • @Dima 警告仅在隐藏实例字段的变量之间,但变量不能隐藏其他变量,它不仅会产生警告,还会产生错误
  • 实例字段,是的。这是最接近 OP 所描述的“全局变量”的东西,不是吗?
【解决方案2】:

在 java 中,您有公共和私有访问修饰符来控制变量的可访问性,但是如果您在类中声明一个变量,它将是一个全局变量,与类方法中的变量相比,它是局部变量。方法之外。没有绝对的全局和局部变量,您必须为新变量声明和定义新变量名称。

public class abc{
    public int a; //global and accessible by every class outside this class too 
    private int b; //global and accessible only within this class
    private void m(){
        int x; //local and accessible only within this method 
    }
}

另外你可以做到这一点

public void m(){
    for(;;){
        int a;
    }
    for(;;){
        int a;
    }
}

但你不能这样做

public void m(){
    int a;
    for(;;){
        int a;
    }
}

希望对你有所帮助。

【讨论】:

    【解决方案3】:

    在 Java 中我正在尝试做类似的事情,但我得到了错误

    变量 rawURL 已在方法 run() 中定义

    JLS 解释了您收到错误的原因:

    6.4。阴影和遮蔽

    如果使用局部变量v 的名称来声明v 范围内的新变量,则会出现编译时错误,除非新变量是在声明为的类中声明的在v范围内。

    要解释v 的范围是什么,请查看我解释过的answer

    基本上,如果将其与 Perl 进行比较,范围是“单向”而不是“双向”。

    void method1() {
    
        int x;
        {
            int y = x; // O.K. - x is in scope.
            int x = y; // Not O.K. - x is in scope and was already declared.
        }
        x = y; // Not O.K. - y is not in scope.
    }
    

    可以做什么,就是这样:

    void method2() {
    
        int x;            
        class InsideClass {                             
            {             
                int y = x;
                int x = y;
            }             
        }
    }      
    

    但这可能对您的需求有点过头了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多