实例级最终变量的 Java 编译时错误,并且未给出方法级局部变量



为什么当我们不初始化方法级局部最终变量时,java编译器没有给出任何编译时错误?

(但是当实例级最终变量未初始化时,它会给出 en 错误(。

public class FinalKeyword
{
final int j; // error: the blank final field j may not have been initialized.
public static void main(String[] args)
{
final int k; // not giving any Compile time error!
}
}

事情是:一旦您将main()方法更改为

final int k;//Not Giving any Compile time error
System.out.println(k); //different story now!

您也会收到有关k未初始化的错误!

关键是:

  • 编译器必须确保其他源代码现在不可见......能够毫无问题地做new FinalKeyword()。因此,它不能让你保持j不初始化。
  • 但是那main()方法...即使另一个方法调用此main()方法 - 这也很好。该方法无济于事!换句话说 - 定义一个在方法中不使用的变量不是问题!因为没有办法到达该变量!

编译器必须防止您陷入"偶然"未初始化变量的情况。当您调用具有此类变量的方法时...但从不使用它们——那只是"不在乎"。

惊喜:当我们去的时候

public class FinalTest {
public static void main(String args[]) {
final int k;
}
}

然后我们使用Javap来获得反编译的字节码:

public static void main(java.lang.String[]);
Code:
0: return     

这是javac通过简单地丢弃未使用的变量进行一些优化的罕见情况之一。额外的有趣事实:即使将我的示例更改为k=5;- 您会发现类文件仍然只包含return

j

是类的一个字段。k不是。您需要初始化类构造函数中的最终字段。您的类正在使用默认的隐式构造函数,该构造函数不初始化字段。

它没有给你局部变量警告的原因是因为你不使用它。如果要使用未初始化的局部变量,则会收到错误:

public static void main(String[] args)
{
final int k;
if (k < 5) {
// whatever
}
}

至于为什么编译器不够聪明,不知道你也没有使用该字段,我不确定。由于继承、访问级别等原因,它可能更复杂。

通常,如果编译器遇到未初始化时可能访问final或在初始化时设置的情况,则会出现错误。

必须初始化类的final字段,因为有人可以随时访问它们。如果它是包私有、受保护或公共的,则其他代码可以直接访问该字段,并且他们希望对其进行初始化。即使该字段private,有人也可以反映它并尝试访问它,因此编译器一定不能忽略它。

方法的final局部变量是方法内部的,如果不修改一些字节码,就无法在方法内部反映,因此编译器不需要那么严格。相反,编译器执行控制流分析以映射何时分配字段和不分配字段,如果在未分配的情况下使用它,它将引发错误,如果从未使用或在明确分配时使用字段,它将是满意的。

void meth0() {
final String s;
// Compiler: s is never used; I don't care.
}
void meth1() {
final String s;
// s is definitely unassigned
if(something()) {
s = "something";
// s is definitely assigned
System.out.println(s);
} else {
// s is definitely unassigned
s = "other";
// s is definitely assigned
System.out.println(s);
}
// if-branch def. assigns s, else-branch def. assigns s
// Ergo: s is def. assigned
somethingElse(s);
// Compiler: control flow checks out; code is valid
}
void meth2() {
final String s;
// def. unass.
if(something()) {
s = "something";
// def ass.
}
// s is in undetermined state
// s = ""; // s may be assigned; error
// use(s); // s may not be assigned; error
// s is now totally unusable. Nice job breaking it, hero!
}

最新更新