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

Aus*_*yde 159 java compile-time-constant

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

public abstract class Foo {
    ...
    public static final int BAR;
    public static final int BAZ;
    public static final int BAM;
    ...
}
Run Code Online (Sandbox Code Playgroud)

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

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";
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,当我编译时,我constant expression required在每个3个案例标签上都会出错.

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

Ste*_*n C 138

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

虽然从字段初始化后执行的任何代码的角度看它们是不变的,但它们不是JLS要求的编译时常量; 有关常量表达式所需内容的定义,请参见§15.28常量表达式.这是指§4.12.4最终变量,它定义了一个"常量变量",如下所示:

我们调用一个原始类型或类型String的变量,它是最终的,并使用编译时常量表达式(第15.28节)作为常量变量进行初始化.变量是否是常量变量可能对类初始化(第12.4.1节),二进制兼容性(第13.1节,第13.4.9节)和明确赋值(第16节)有影响.

在您的示例中,Foo.BA*变量没有初始值设定项,因此不符合"常量变量"的条件.修复很简单; 将Foo.BA*变量声明更改为具有编译时常量表达式的初始值设定项.

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

当然,您可以将代码更改为使用enum而不是int常量,但这会带来另一个问题.如果你使用a defaultin,case必须包括一个enum案例,即使你有case每个已知的价值enum; 请参阅此代码中为什么在枚举上需要默认值?


Ton*_*nis 73

需要获得常量表达式,因为您将值保留在常量之外.尝试:

public abstract class Foo {
    ...
    public static final int BAR=0;
    public static final int BAZ=1;
    public static final int BAM=2;
    ...
}
Run Code Online (Sandbox Code Playgroud)


Teo*_*nke 45

我在Android上遇到此错误,我的解决方案就是使用:

public static final int TAKE_PICTURE = 1;
Run Code Online (Sandbox Code Playgroud)

代替

public static int TAKE_PICTURE = 1;
Run Code Online (Sandbox Code Playgroud)

  • 我知道这是一个不同的问题,但是因为我和我一起来这里可以帮助其他人处于相同的情况. (4认同)
  • 只是为了澄清:这可以通过使静态属性最终来解决您的错误.在我最初的问题中,问题是最终的静态属性缺少初始化器,使其成为常量,但不是编译时常量.请参阅接受的答案了解详情. (3认同)

She*_*per 29

因为那些不是编译时常量.请考虑以下有效代码:

public static final int BAR = new Random().nextInt();
Run Code Online (Sandbox Code Playgroud)

您只能知道BAR运行时的值.

  • Thilo的语句编译但是switch语句抱怨_constant expression required_.此外,不能连续两个`new Random().nextInt()`返回相同的值? (4认同)
  • @Tony:这是件好事.它不会编译,因为它没有使用编译时常量进行初始化.见斯蒂芬接受的答案.如果确实编译了,那么随机整数将被硬编码到类中,结果非常不可预测. (2认同)

the*_*sic 17

您可以使用此示例中的枚举:

public class MainClass {
enum Choice { Choice1, Choice2, Choice3 }
public static void main(String[] args) {
Choice ch = Choice.Choice1;

switch(ch) {
  case Choice1:
    System.out.println("Choice1 selected");
    break;
 case Choice2:
   System.out.println("Choice2 selected");
   break;
 case Choice3:
   System.out.println("Choice3 selected");
   break;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

来源: 带枚举的switch语句


Din*_*esh 8

我建议使用以下方式:

public enum Animal {
    DOG("dog"), TIGER("tiger"), LION("lion");
    private final String name;

    @Override
    public String toString() {
        return this.name;
    }
}


public class DemoSwitchUsage {

     private String getAnimal(String name) {
         Animal animalName = Animal.valueOf(name);
         switch(animalName) {
         case DOG:
             // write the code required.
             break;
         case LION:
             // Write the code required.
             break;
         default:
             break;
         }
     }
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为枚举应该具有以下构造函数:`private Animal(String name) { this.name = name; }` (2认同)

Sam*_*rad 5

这是很久以前就回答过的问题,可能不相关,但以防万一。当我遇到这个问题时,我只是使用了一个if语句而不是switch,它解决了错误。这当然是一种解决方法,可能不是“正确”的解决方案,但就我而言,这已经足够了。

编辑:2021.01.21

这个答案有点误导,我想澄清一下。

  1. switch用an替换语句if不应被视为 goto 解决方案,软件开发中存在switch和 的概念是有充分理由if的,并且在两者之间进行选择时需要考虑性能问题。
  2. 尽管我提供了针对所出现错误的解决方案,但我的回答没有说​​明问题发生的“原因”,而是提供了解决问题的方法。

在我的具体情况下,使用if语句就足以解决问题。开发人员应该花些时间来确定这是否是解决您当前遇到的问题的正确解决方案。

因此,这个答案应该仅被视为我在第一个回复中所述的特定情况下的解决方法,而绝不是这个问题的正确答案

  • 这是一种解决方法,而不是问题的答案 (8认同)
  • 可能是因为它是一个 IF 语句,我们专门试图通过 switch 来避免它 (3认同)
  • 我投了反对票,因为这里的问题不是“如何”解决问题,而是“为什么”发生问题。我认为你的回答是断章取义的。另外,如果你是完美主义者,你应该意识到`switch`通常比长`if-else`更快,因为`switch`只检查条件*一次*,而使用`if-else`你可能需要检查*在找到合适的之前先考虑所有*条件。 (2认同)