final变量和编译时常量的区别

28

final变量和编译时常量之间有什么区别?

考虑以下代码:

final int a = 5;
final int b;
b=6;
int x=0;
switch(x)
{
     case a: //no error
     case b: //compiler error
}

这是什么意思?何时和如何为最终变量分配值?运行时会发生什么?编译时会发生什么?为什么我们应该为 switch 提供一个编译时常量?Java 的哪些其他结构需要编译时常量?


请参考JLS中有关该主题的链接。 - Tarun Mohandas
5个回答

28

问题在于,所有的case:语句必须在编译时达到最终状态。你的第一个语句已经到达最终状态a将百分之百地没有除5以外的其他值。

final int a = 5;

然而,对于b不保证如此。如果在b周围有一个if语句会怎么样呢?

final int b;
if(something())
   b=6;
else
   b=5;

7

这是什么意思?

这意味着“b”不是编译时常量表达式,而JLS要求它是。

什么时候和如何为final变量赋值?

正式地说,当执行赋值语句或初始化器时。

但实际上,如果final声明为编译时常量,则表达式在编译时计算,并且其值被硬编码到代码中。

在运行时会发生什么,在编译时会发生什么?

见上文。

为什么我们应该给switch一个编译时常量?

因为JLS要求这样做。

这对于字节码编译器来检查switch语句是否格式良好是必要的;即switch常量的值不冲突。它还允许JIT编译器生成针对switch常量实际值进行优化的代码。

Java的哪些其他结构需要编译时常量?

我想不出有其他的,就这些。


3

从编译器角度看,您试图使用一个可能没有初始化的变量b。switch语句被编译成JVM字节码表格或查找表,需要在case语句中使用的值是编译时常量而且唯一的。

final int a = 4; // compiler is sure a is initialized
final int b;// variable b is not guranted to be assigned

例如:尽管这个语句最终会初始化变量b,但编译器无法检测到它。

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

2

switch语句需要一个常量。由于final变量可以延迟初始化,编译器无法确定在case分支中b是否有值。


6
好的,但我仍然没有得到我的问题的答案。 - Tarun Mohandas

2

final int b; 只能被赋值一次,其值在运行时根据条件而定,这就是为什么即使是一个final变量,它也不是编译时常量,尽管它将是一个运行时常量,而案例需要编译时常量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接