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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3827393/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 05:33:47  来源:igfitidea点击:

Java switch statement: Constant expression required, but it IS constant

javacompile-time-constant

提问by Austin Hyde

So, I am working on this class that has a few static constants:

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

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

Then, I would like a way to get a relevant string based on the constant:

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

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";
    }
}

However, when I compile, I get a constant expression requirederror on each of the 3 case labels.

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

I understand that the compiler needs the expression to be known at compile time to compile a switch, but why isn't Foo.BA_constant?

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

采纳答案by Stephen C

I understand that the compiler needs the expression to be known at compile time to compile a switch, but why isn't Foo.BA_ constant?

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

While they are constant from the perspective of any code that executes after the fields have been initialized, they are not a compile time constantin the sense required by the JLS; see §15.28 Constant Expressionsfor the specification of a constant expression1. This refers to §4.12.4 Final Variableswhich defines a "constant variable" as follows:

虽然从字段初始化后执行的任何代码的角度来看,它们都是常量,但它们不是JLS 要求的编译时常量;有关常量表达式1的规范,请参阅§15.28 常量表达式。这指的是§4.12.4 Final Variables,它定义了一个“常量变量”,如下所示:

We call a variable, of primitive type or type String, that is final and initialized with a compile-time constant expression (§15.28) a constant variable. Whether a variable is a constant variable or not may have implications with respect to class initialization (§12.4.1), binary compatibility (§13.1, §13.4.9) and definite assignment (§16).

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

In your example, the Foo.BA* variables do not have initializers, and hence do not qualify as "constant variables". The fix is simple; change the Foo.BA* variable declarations to have initializers that are compile-time constant expressions.

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

In other examples (where the initializers are already compile-time constant expressions), declaring the variable as finalmay be what is needed.

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

You could change your code to use an enumrather than intconstants, but that brings another couple of different restrictions:

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



1 - The constant expression restrictions can be summarized as follows. Constant expressions a) can use primitive types and Stringonly, b) allow primaries that are literals (apart from null) and constant variables only, c) allow constant expressions possibly parenthesised as subexpressions, d) allow operators except for assignment operators, ++, --or instanceof, and e) allow type casts to primitive types or Stringonly.

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

Note that this doesn't include any form of method or lambda calls, new, .class. .lengthor array subscripting. Furthermore, any use of array values, enumvalues, values of primitive wrapper types, boxing and unboxing are all excluded because of a).

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

回答by Sheldon L. Cooper

Because those are not compile time constants. Consider the following valid code:

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

public static final int BAR = new Random().nextInt();

You can only know the value of BARin runtime.

你只能知道BAR在运行时的值。

回答by Tony Ennis

You get Constant expression requiredbecause you left the values off your constants. Try:

需要常量表达式,因为您将值从常量中删除了。尝试:

public abstract class Foo {
    ...
    public static final int BAR=0;
    public static final int BAZ=1;
    public static final int BAM=2;
    ...
}

回答by thenosic

You can use an enum like in this example:

您可以在本例中使用枚举:

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;
    }
  }
}

Source: Switch statement with enum

来源: 带有枚举的 Switch 语句

回答by everton

I recommend you to use enums :)

我建议你使用枚举:)

Check this out:

看一下这个:

public enum Foo 
{
    BAR("bar"),
    BAZ("baz"),
    BAM("bam");

    private final String description;

    private Foo(String description)
    {
        this.description = description;
    }

    public String getDescription()
    {
        return description;
    }
}

Then you can use it like this:

然后你可以像这样使用它:

System.out.println(Foo.BAR.getDescription());

回答by Teo Inke

I got this error on Android, and my solution was just to use:

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

public static final int TAKE_PICTURE = 1;

instead of

代替

public static int TAKE_PICTURE = 1;

回答by Samer Murad

This was answered ages ago and probably not relevant, but just in case. When I was confronted with this issue, I simply used an ifstatement instead of switch, it solved the error. It is of course a workaround and probably not the "right" solution, but in my case it was just enough.

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

回答by Mahdi-Malv

Sometimes the switch variablecan also make that error for example:

有时switch 变量也会导致该错误,例如:

switch(view.getTag()) {//which is an Object type

   case 0://will give compiler error that says Constant expression required

   //...
}

To solve you should cast the variable to int(in this case). So:

要解决此问题,您应该将变量强制转换为 int(在这种情况下)。所以:

switch((int)view.getTag()) {//will be int

   case 0: //No Error

   //...
}

回答by Ojonugwa Jude Ochalifu

Got this error in Android while doing something like this:

在执行以下操作时,在 Android 中出现此错误:

 roleSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

            switch (parent.getItemAtPosition(position)) {
                case ADMIN_CONSTANT: //Threw the error

            }

despite declaring a constant:

尽管声明了一个常量:

public static final String ADMIN_CONSTANT= "Admin";

public static final String ADMIN_CONSTANT= "Admin";

I resolved the issue by changing my code to this:

我通过将代码更改为以下解决了该问题:

roleSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

            String selectedItem = String.valueOf(parent.getItemAtPosition(position));
            switch (selectedItem) {
                case ADMIN_CONSTANT:

            }

回答by Gian Gomen

In my case, I was getting this exception because

就我而言,我收到此异常是因为

switch (tipoWebServ) {
                            case VariablesKmDialog.OBTENER_KM:
                                resultObtenerKm(result);
                                break;
                            case var.MODIFICAR_KM:
                                resultModificarKm(result);
                                break;
                        }

in the second case I was calling the constant from the instance var.MODIFICAR_KM:but I should use VariablesKmDialog.OBTENER_KMdirectly from the class.

在第二种情况下,我从实例调用常量,var.MODIFICAR_KM:但我应该VariablesKmDialog.OBTENER_KM直接从类中使用。