小编典典

Java switch 语句:需要常量表达式,但它是常量

all

所以,我正在研究这个有一些静态常量的类:

public abstract class Foo {
    ...
    public static final int BAR;
    public static final int BAZ;
    public static final int BAM;
    ...
}

然后,我想要一种基于常量获取相关字符串的方法:

public static String lookup(int constant) {
    switch (constant) {
        case Foo.BAR: return "bar";
        case Foo.BAZ: return "baz";
        case Foo.BAM: return "bam";
        default: return "unknown";
    }
}

但是,当我编译时,constant expression required3 个案例标签中的每一个都出现错误。

我知道编译器需要在编译时知道表达式才能编译开关,但为什么不是Foo.BA_常量?


阅读 250

收藏
2022-06-24

共1个答案

小编典典

我知道编译器需要在编译时知道表达式才能编译开关,但为什么 Foo.BA_ 不是常量?

虽然从在字段初始化后执行的任何代码的角度来看它们是恒定的,但它们不是 JLS 要求的 编译时间常数有关常量表达式 1的规范,请参见拥抱
15.28
常量表达式
。这指的是拥抱4.12.4
最终变量
,它定义了一个“常量变量”,如下所示:
__

我们将原始类型或字符串类型的变量称为最终变量,并使用编译时常量表达式(拥抱15.28)进行初始化,称为常量变量。变量是否为常量变量可能对类初始化(搂12.4.1)、二进制兼容性(搂13.1、搂13.4.9)和明确赋值(搂16)有影响。

在您的示例中, Foo.BA 变量没有初始化程序,因此不符合“常量变量”的条件。修复很简单;将 Foo.BA
变量声明更改为具有编译时常量表达式的初始化程序。

在其他示例中(初始化程序已经是编译时常量表达式),将变量声明为final可能是需要的。

您可以更改代码以使用 anenum而不是int常量,但这会带来另外几个不同的限制:

  • 必须 包含一个default案例,即使您拥有case; 的每个已知值enum
  • case标签必须都是显式enum值,而不是评估为值的表达式enum

1 - 常量表达式的限制可以总结如下。常量表达式 a) 只能使用原始类型String,b)
只允许作为字面量的基本类型(除了null)和常量变量,c) 允许可能用括号括起来作为子表达式的常量表达式,d)
允许除赋值运算符之外的运算符,++,--instanceof, 和e) 允许或String仅允许类型转换为原始类型。

请注意,这不包括任何形式的方法或 lambda 调用、new.class.length或数组下标。此外,由于
a),任何使用数组值、enum值、原始包装类型的值、装箱和拆箱都被排除在外。

2022-06-24