常数表达式
常量表达式是一个表达式,它产生一个基本类型或一个 String,并且其值可以在编译时计算为文字。表达式必须在不抛出异常的情况下进行求值,并且必须仅由以下内容组成:
-
原始和字符串文字。
-
类型转换为基本类型或
String。 -
以下一元运算符:
+,-,~和!。 -
以下二元运算符:
*,/,%,+,-,<<,>>,>>>,<,<=,>,>=,==,!=,&,^,|,&&和||。 -
三元条件算子
?:。 -
带括号的常量表达式。
-
引用常量变量的简单名称。 (常量变量是声明为
final的变量,其中初始化表达式本身是一个常量表达式。) -
<TypeName> . <Identifier>形式的合格名称,用于引用常量变量。
请注意,上面的列表不包括 ++和 --,赋值运算符,class 和 instanceof,方法调用以及对常规变量或字段的引用。
String 类型的常量表达式导致 interned``String,并且使用 FP-strict 语义评估常量表达式中的浮点运算。
用于常量表达式
可以在任何可以使用普通表达式的地方使用常量表达式(几乎)。但是,它们在以下情况下具有特殊意义。
switch 语句中的 case 标签需要常量表达式。例如:
switch (someValue) {
case 1 + 1: // OK
case Math.min(2, 3): // Error - not a constant expression
doSomething();
}
当赋值右侧的表达式是常量表达式时,赋值可以执行原始缩小转换。只要常量表达式的值在左侧类型的范围内,就允许这样做。 (参见 JLS 5.1.3 和 5.2 )例如:
byte b1 = 1 + 1; // OK - primitive narrowing conversion.
byte b2 = 127 + 1; // Error - out of range
byte b3 = b1 + 1; // Error - not a constant expession
byte b4 = (byte) (b1 + 1); // OK
当常量表达式用作 do,while 或 for 中的条件时,它会影响可读性分析。例如:
while (false) {
doSomething(); // Error - statenent not reachable
}
boolean flag = false;
while (flag) {
doSomething(); // OK
}
(请注意,这不适用于 if 语句 .Java 编译器允许 if 语句的 then 或 else 块无法访问。这是 C 和 C++中条件编译的 Java 模拟。)
最后,一个类或具有常量表达式初始化器的接口中的 static final 字段被急切初始化。因此,即使在类初始化依赖图中存在循环,也可以保证在初始化状态下观察这些常量。
有关更多信息,请参阅 JLS 15.28。常数表达式 。