为什么else if和else在这里的行为不同?



当我这样做时,

if(a>=b && a>=c) {
max = a;
} else if (b>=a && b>=c) {
max = b;
} else if (c>=a && c>=b) {
max = c;
}
System.out.println(max);

它给出一个错误(java: variable max可能没有被初始化),但是当我这样做时,

if(a>=b && a>=c) {
max = a;
} else if (b>=a && b>=c) {
max = b;
} else {
max = c;
}
System.out.println(max);

它的工作原理。为什么会这样?

在第一种情况下,所有编译器看到的是您有3个条件语句为max设置值。因此,它认为存在一个可能的路径,其中所有条件都不为真,在这种情况下max不会被赋值。

你和我可以看看这些条件,并明白其中一个必须是正确的。编译器不会考虑这些,它只是假设每个条件都可能为假。

当存在一个没有条件的else时,编译器可以保证至少有一个赋值将被执行。因此没有错误。

在else if中,必须有一个条件。只有当条件满足时,它才会进入。在第一种情况下,如果所有条件都为假,那么max将保持未初始化,而在第二种情况下,如果if和else都为假,则else部分肯定会执行。因此,max在所有情况下都有一定的价值。

我假设你的变量声明看起来像这样:

int a = 0;
int b = 0;
int c = 0;
int max;

在System.out.println(max)中调用max时发生变量未初始化错误最重要的区别在这一部分:# 1

} else {
max = c;
} 

# 2

} else if (c>=a && c>=b) {
max = c;
}

那么,for case#1编译器100%确定,即使您没有陷入任何前面的if-conditions ((a>=b &&)a>=c) (b>=a &B>=c)),您将在else块中结束,该块将处理其余情况。For case#2,但是,if树的最后一部分仍然是一个条件。编译器假定存在这样一种可能性,即(a>=b &&a>=c), (b>=a &&>=c)也不(c>=a &&C>=b)为真,因此,认为Max未初始化。

简而言之:else语句的存在保证了max是设置的。

编译器应用流分析检查局部变量是否被明确赋值,并且编译器足够聪明1检测在所有可能的代码路径中max在使用之前是否被设置。

在Java语言规范第16章中有详细的定义。


1正如Feuermurmel在注释中已经说过的,编译器不分析条件表达式。从逻辑上讲,条件之一必须为真,我们人类肯定知道。但是这种对编译器的分析不会达到那个程度,可能是为了减少复杂性。

在您的第一个示例中,Java不确定if/else块是否被执行。所以,如果你输出max,它可能仍然是空的。在第二个示例中,无论变量max是什么,它都会有一个值(c),如果不是在它上面的if/else链中确定的其他东西。这也取决于您如何初始化max。例如,如果像这样声明max

int max;
if(a>=b && a>=c) {
max = a;
} else if (b>=a && b>=c) {
max = b;
} else if (c>=a && c>=b) {
max = c;
}
System.out.println(max);

max从来没有被赋值,所以它是null。如果你实例化它

int max = 0;
if(a>=b && a>=c) {
max = a;
} else if (b>=a && b>=c) {
max = b;
} else if (c>=a && c>=b) {
max = c;
}
System.out.println(max);

即使max在if/else链中没有改变,它仍然有一个值要输出。

这个问题的答案很简单。当if语句不为真时,总是会运行else语句。您的IDE抱怨max可能没有初始化,因为它实际上不理解代码。为了避免它,你可以这样做:

int max = 0;
if(a>=b && a>=c) {
max = a;
} else if (b>=a && b>=c) {
max = b;
} else if (c>=a && c>=b) {
max = c;
}
System.out.println(max);

最新更新