常数表达式
常量表达式是一个表达式,它产生一个基本类型或一个 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。常数表达式 。