2012-05-30 46 views
81

我有一个关于Java开关的疯狂问题。声明和初始化Java开关内的变量

int key = 2; 

switch (key) { 
    case 1: 
     int value = 1; 
     break; 
    case 2: 
     value = 2; 
     System.out.println(value); 
     break; 
    default: 
     break; 
} 

场景1 - 当key是二它成功打印的价值为2
场景2 - 当我要去case 2:评论value = 2它叫声称局部变量的值可能没有已初始化为

问题:

方案1:如果执行流不会去case 1:(当key = 2),那么它是如何知道变量的值作为int的类型?方案2:如果编译器知道值变量的类型为int,那么它必须访问表达式case 1:(声明和初始化)。那么为什么它sqawrk当我要在case 2:value = 2评论,说本地变量值可能尚未初始化

+9

这不是一个疯狂的问题,这是一个非常好的问题。 – biziclop

+0

[变量在开关盒中的范围]的可能重复(http://stackoverflow.com/questions/3894119/variables-scope-in​​-a-switch-case) –

+0

@PhilippeCarriere其实,我认为它应该是相反的 - 这里的答案更好(即使帖子更新),因为直接引用了JLS,并且在该帖子的不同答案中涵盖了该问题。 [另见](http://meta.stackoverflow.com/questions/251938/should-i-flag-a-question-as-duplicate-if-it-has-received-better-answers)。 – Tunaki

回答

96

基本上,开关语句在范围界定方面很奇怪。从section 6.3 of the JLS

局部变量声明的块中的范围(§14.4)是在其中出现的声明,开始与它自己的初始化,并且包括任何进一步说明符在右侧的块的其余部分局部变量声明语句。

在你的情况,case 2是在同一case 1后它的出现,即使case 1永远不会执行......所以,局部变量是在范围和可供尽管你逻辑从不“执行”声明。 (即使初始化,声明也不是“可执行”的。)

如果你注释掉value = 2;赋值,编译器仍然知道你指的是哪个变量,但是你不会经过任何赋值的执行路径,这就是为什么你得到一个错误的原因当你试图读取任何其他未明确分配的局部变量时,你会这样做。

我强烈建议你而不是使用在其他情况下声明的局部变量 - 它会导致高度混淆的代码,正如你所见。当我介绍switch语句中的局部变量(我尝试很少这样做 - 的情况下应该是很短的,理想情况下)我通常喜欢引入一个新的范围:

case 1: { 
    int value = 1; 
    ... 
    break; 
} 
case 2: { 
    int value = 2; 
    ... 
    break; 
} 

我相信这是更清晰。

+8

+1“虽然初始化是”声明不是真的“可执行”。“谢谢Skeet的建议。 – namalfernandolk

18

http://www.coderanch.com/t/447381/java-programmer-SCJP/certification/variable-initialization-within-case-block

声明是在编译时处理,不依赖于你的代码的 执行流程。由于value在开关块的本地 范围内声明,因此它可用于该块的任何地方,从 其声明点开始。

+0

为什么这个答案被upvoted?它不回答这个问题,不像保罗或者飞碟的答案...... –

+6

它的确如此。所以,+1,一分钱,也从我身边。 –

18

该变量已被声明(作为一个int),但未初始化(分配一个初始值)。思而行的:

int value = 1; 

由于:

int value; 
value = 1; 

int value部分告诉在你有一个变量,名为值是一个int编译时,编译器。 value = 1部分初始化它,但是这发生在运行时,并且如果没有输入该交换机的该分支,则根本不会发生。

+0

对于编译时和运行时的声明和初始化的很好的解释。 – namalfernandolk