常数表达式

常量表达式是一个表达式,它产生一个基本类型或一个 String,并且其值可以在编译时计算为文字。表达式必须在不抛出异常的情况下进行求值,并且必须仅由以下内容组成:

  • 原始和字符串文字。

  • 类型转换为基本类型或 String

  • 以下一元运算符:+-~!

  • 以下二元运算符:*/%+-<<>>>>><<=>>===!=&^|&&||

  • 三元条件算子 ? :

  • 带括号的常量表达式。

  • 引用常量变量的简单名称。 (常量变量是声明为 final 的变量,其中初始化表达式本身是一个常量表达式。)

  • <TypeName> . <Identifier> 形式的合格名称,用于引用常量变量。

请注意,上面的列表不包括 ++--,赋值运算符,classinstanceof,方法调用以及对常规变量或字段的引用。

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.35.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

当常量表达式用作 dowhilefor 中的条件时,它会影响可读性分析。例如:

while (false) {
    doSomething();           // Error - statenent not reachable
}
boolean flag = false;
while (flag) {
    doSomething();           // OK
}

(请注意,这不适用于 if 语句 .Java 编译器允许 if 语句的 thenelse 块无法访问。这是 C 和 C++中条件编译的 Java 模拟。)

最后,一个类或具有常量表达式初始化器的接口中的 static final 字段被急切初始化。因此,即使在类初始化依赖图中存在循环,也可以保证在初始化状态下观察这些常量。

有关更多信息,请参阅 JLS 15.28。常数表达式