在Java中,究竟是什么构成了"初始化局部变量"?

时间:2014-04-21 23:01:02

标签: java

说我在本地方法中有一段代码

int a = 5, b;

然后一些代码来间接初始化B,例如

if (true) b = 5;  // legal 
if (someBool) b = 10; else b = 7; // legal
if (false) b = 5;  // illegal 

非法,即使B总是被初始化

if (a > 10)
b = 4;
if (a <= 10)
b = 4;

我的问题是,在何种情况下,可以合理地考虑局部变量&#34;初始化&#34;?

2 个答案:

答案 0 :(得分:4)

如果编译器可以很容易地推断出每个可能的代码路径将通过已设置值的路径,则可以认为局部变量是“初始化的”。

  • if(true)可以确定始终运行。
  • if(false)可以确定永不运行。
  • if/else可以确定至少运行其中一个分支,因此如果要保证初始化,必须在每个分支中分配变量。同样的原则适用于if/else if/.../else
  • switch语句将运行可能的case之一,或者会遇到default个案例,因此如果您在所有这些位置分配变量,那么可以保证初始化。

在进行此确定时,Java编译器不会在方法的各个点检查每个变量的所有可能值,因为变量是变量 - 它们可以更改。但是,如果值可以被视为常量,那么它可以安全地假设它们不会改变。

例如,编译器不关心您是否分配变量并且永远不会在代码中更改它:

boolean val = true;
if(val) {
     b = 5;
}

调试器和事物使您可以即时更改val的值,因此编译器不会在此进行任何假设。但是,如果您使val 常量,通过将其声明为final并使用常量或字面值初始化它,那么编译器会将其视为与您完全相同d在代码中使用常量值。

final boolean val = true;
if(val) {                 // Same as if you'd said `if(true)`
     b = 5;
}

这些常量也可以链接,编译器会将它们简化为常量值,而不是维护较长的表达式和运算符:

final int five = 5;
final int four = five - 1; // Same as `four = 5 - 1`, or `four = 4`
final boolean val = five > four;
if(val) {           // Same as `if(5 > 4)`, or `if(true)`
     b = 5;
}

如需进一步阅读,请查看Java Specs。 (给Radiodef寻找合适的部分的帽子提示。)

答案 1 :(得分:0)

在这种情况下:

if (false) b = 5;  // illegal

编译器抛出异常,因为if(false)可以在编译时擦除。即使分析一块不会被任何手段执行的代码块也是徒劳的。

在这种情况下:

int a = 5, b;
if (a > 10)
b = 4;
if (a <= 10)
b = 4;

由于a可以更改其值,编译器无法确保将执行该段代码。在这种情况下,您可以通过将a标记为final并为其指定一个文字int值(编译器可以理解)来修复

final int a = 5;
int b;
if (a > 10)
    b = 4;
if (a <= 10)
    b = 4;

但请注意,您仍然可以通过为final int a提供编译器无法确定的值来破坏此代码:

final int a = foo();
int b;
if (a > 10)
    b = 4;
if (a <= 10)
    b = 4;

//...

int foo() {
    return 5;
}

更多信息: