Java 变量[x]已在方法[y]中定义,但作用域不同

Java 变量[x]已在方法[y]中定义,但作用域不同,java,netbeans,scope,Java,Netbeans,Scope,我不知道为什么这个代码不起作用。正如您所看到的,变量x显然存在于两个地方,但它们在两个不同的范围内。在下面的示例中,它们位于两个不同的case语句中,第二个位于另一个if语句中。有什么好处?为什么会出现这样的错误,即变量“已定义”?最新的编译器和Netbeans。我习惯C++,这不是问题。谢谢 package testapp; public class TestApp { /** * @param args the command line arguments *

我不知道为什么这个代码不起作用。正如您所看到的,变量
x
显然存在于两个地方,但它们在两个不同的范围内。在下面的示例中,它们位于两个不同的
case
语句中,第二个位于另一个
if
语句中。有什么好处?为什么会出现这样的错误,即变量“已定义”?最新的编译器和Netbeans。我习惯C++,这不是问题。谢谢

package testapp;

public class TestApp {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        int decisionValue1 = Integer.parseInt(System.console().readLine());
        int decisionValue2 = Integer.parseInt(System.console().readLine());

        switch (decisionValue1)
        {
            case 1:
                int x = decisionValue1;
                System.out.println(x);
                break;

            case 2:
                if (decisionValue2 == 4)
                {
                    int x = decisionValue2;
                    System.out.println(x);
                }

                break;
            default:
                break;
        }
    }    
}
具体而言,错误是:

[Source Dir]: error: variable x is already defined in method main(String[])
编辑:

嘿,伙计们。由于最初的响应集中在
switch
语句上,因此我在下面做了一个修改示例。没有
switch
语句,但有相同的错误

public class TestApp {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        int decisionValue1 = Integer.parseInt(System.console().readLine());
        int decisionValue2 = Integer.parseInt(System.console().readLine());

        int x = decisionValue1;

        if (decisionValue1 == 4)
        {
            int x = decisionValue2;
            System.out.println(x);
        }
    }    
}

因为
switch
语句不必
break
,执行流可以继续到下一种情况,它们不在不同的范围内。第二个
x
位于
if
语句中的事实不会改变这一点,因为
if
仍在
开关中

当您添加第二个
x
时,您将等效地执行以下操作:

+-------+
|   x   |
| +---+ |
| | x | |
| +---+ |
+-------+
如您所见,同一个框中有两个
x
s(不允许)

x
的第一个声明周围添加大括号:

case 1:
{
    int x = decisionValue1;
    System.out.println(x);
    break;
}
将产生如下图片:

+-------+
| +---+ |
| | x | |
| +---+ |
| +---+ |
| | x | |
| +---+ |
+-------+

这是允许的。

因为
开关
语句不必
中断
,执行流可以继续到下一种情况,它们不在不同的范围内。第二个
x
位于
if
语句中的事实不会改变这一点,因为
if
仍在
开关中

当您添加第二个
x
时,您将等效地执行以下操作:

+-------+
|   x   |
| +---+ |
| | x | |
| +---+ |
+-------+
如您所见,同一个框中有两个
x
s(不允许)

x
的第一个声明周围添加大括号:

case 1:
{
    int x = decisionValue1;
    System.out.println(x);
    break;
}
将产生如下图片:

+-------+
| +---+ |
| | x | |
| +---+ |
| +---+ |
| | x | |
| +---+ |
+-------+

这是允许的。

这是因为两件事:

  • 作用域是嵌套的
  • 开关中的所有内容都在一个范围内——不同的情况并不重要
  • 因此,开关在
    案例1
    部分中声明一个
    intx
    。然后,在
    案例2
    部分中,您的
    if
    块声明了一个嵌套的作用域,该作用域也尝试声明
    int x
    ,这是编译器不允许的

    一种解决方案是在
    案例1
    部分中放置一个“匿名块”。您可以将块放在可以放置语句的任何位置,它会创建自己的作用域:

    case 1:
    { // anonymous scope
        int x = ...
    }
    
    这样,
    开关中最外层的作用域不会声明
    intx
    ,您就可以了


    有趣的是,这正是您的
    if
    语句所发生的事情!如果(条件)
    ,则必须遵循的东西只是一个单独的语句;大多数情况下,该语句是一个块,但在这方面,该块as语句与代码中“随机”放置的任何语句没有区别。

    这是由于两个原因:

  • 作用域是嵌套的
  • 开关中的所有内容都在一个范围内——不同的情况并不重要
  • 因此,开关在
    案例1
    部分中声明一个
    intx
    。然后,在
    案例2
    部分中,您的
    if
    块声明了一个嵌套的作用域,该作用域也尝试声明
    int x
    ,这是编译器不允许的

    一种解决方案是在
    案例1
    部分中放置一个“匿名块”。您可以将块放在可以放置语句的任何位置,它会创建自己的作用域:

    case 1:
    { // anonymous scope
        int x = ...
    }
    
    这样,
    开关中最外层的作用域不会声明
    intx
    ,您就可以了


    有趣的是,这正是您的
    if
    语句所发生的事情!如果(条件)
    ,则必须遵循的东西只是一个单独的语句;大多数情况下,该语句是一个块,但在这方面,该块作为语句与代码中“随机”放置的任何语句没有区别。

    您需要大括号来更改范围。类似的问题:@ChrisThompson不一定。范围可以在没有大括号的情况下更改(例如,一行if语句)。它们不在不相交的范围内。第一个x的范围是整个case语句。提示可能重复:用
    {}
    包围
    案例1
    的“主体”。您需要大括号来更改范围。类似的问题:@ChrisThompson不一定。范围可以在没有大括号的情况下更改(例如,一行if语句)。它们不在不相交的范围内。第一个x的范围是整个case语句。提示可能重复:用
    {}
    包围
    案例1
    的“主体”。谢谢。我可以理解,编译器可能没有足够的“聪明”来认识到最后有一个无条件的break语句——我可以接受这一点。但是,“if”语句确实创建了一个新的本地范围。。不是吗?或者这只是我不得不忍受的东西?。@phoenyx是的,但它嵌套在交换机的作用域中,声明
    int x
    @phoenyx-Java不允许在同一局部作用域中使用相同名称的多个变量。谢谢大家。只是澄清一下,子作用域不会在Java中创建“新作用域”——这样子作用域(内方)中的引用只引用最里面的声明?我想你的例子就是这么说的。这不是在C++中的情况。令人惊讶的我还用一个“非切换”的例子编辑了我的原始问题。同样的结果,谢谢。我可以理解,编译器可能没有足够的“聪明”来认识到最后有一个无条件的break语句——我可以接受这一点。但是,“if”语句确实创建了一个新的本地范围。。不是吗?或者这只是我必须忍受的东西?@Phoenyx是的,但这是我的智慧