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

时间:2010-09-30 03:02:44

标签: java compile-time-constant

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

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

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

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

13 个答案:

答案 0 :(得分:134)

  

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

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

  

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

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

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

您可以将代码更改为使用enum而不是int常量,但这会带来另外两种不同的限制:


1 - 常量表达式限制可归纳如下。常量表达式a)只能使用原始类型和String,b)允许只有文字的原色(除了null)和只有常量变量,c)允许常量表达式可能括约为子表达式,d)允许运算符除外的运算符++--instanceof和e)允许对基本类型进行类型转换,或仅允许String

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

答案 1 :(得分:69)

你得到所需的常量表达式,因为你将值保留在常量上。尝试:

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

答案 2 :(得分:41)

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

public static final int TAKE_PICTURE = 1;

而不是

public static int TAKE_PICTURE = 1;

答案 3 :(得分:29)

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

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

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

答案 4 :(得分: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;
    }
  }
}

来源: Switch statement with enum

答案 5 :(得分:3)

这在很久以前得到了解答,可能不相关,但以防万一。 当我遇到这个问题时,我只使用x = 1.2; h = 10.^(-20:-1); f1= 2*cos(x+h/2).*sin(h/2); f1=f1./h; 语句而不是if,它解决了错误。 它当然是一种解决方法,可能不是“正确”的解决方案,但在我的情况下,它就足够了。

答案 6 :(得分:0)

有时切换变量也会出现错误,例如:

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

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

   //...
}

要解决此问题,您应该将变量强制转换为int(在本例中)。所以:

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

   case 0: //No Error

   //...
}

答案 7 :(得分:0)

在执行以下操作时遇到了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

            }

尽管声明了一个常量:

public static final String ADMIN_CONSTANT= "Admin";

我通过将代码更改为此来解决了这个问题:

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:

            }

答案 8 :(得分:0)

在我的情况下,我收到此异常是因为

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

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

答案 9 :(得分:0)

如果在开关盒中使用它,那么即使在将该值插入开关中之前,也需要获取枚举的类型。例如:

  

SomeEnum someEnum = SomeEnum.values()[1];

switch (someEnum) {
            case GRAPES:
            case BANANA: ...

枚举类似于:

public enum SomeEnum {

    GRAPES("Grapes", 0),
    BANANA("Banana", 1),

    private String typeName;
    private int typeId;

    SomeEnum(String typeName, int typeId){
        this.typeName = typeName;
        this.typeId = typeId;
    }
}

答案 10 :(得分:0)

以下代码不言自明, 我们可以在开关盒中使用枚举:

/**
 *
 */
enum ClassNames {
    STRING(String.class, String.class.getSimpleName()),
    BOOLEAN(Boolean.class, Boolean.class.getSimpleName()),
    INTEGER(Integer.class, Integer.class.getSimpleName()),
    LONG(Long.class, Long.class.getSimpleName());
    private Class typeName;
    private String simpleName;
    ClassNames(Class typeName, String simpleName){
        this.typeName = typeName;
        this.simpleName = simpleName;
    }
}

基于枚举的类值可以映射:

 switch (ClassNames.valueOf(clazz.getSimpleName())) {
        case STRING:
            String castValue = (String) keyValue;
            break;
        case BOOLEAN:
            break;
        case Integer:
            break;
        case LONG:
            break;
        default:
            isValid = false;

    }

希望它会有所帮助:)

答案 11 :(得分:0)

我建议使用以下方式:

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

答案 12 :(得分:-1)

我建议你使用枚举:)

检查出来:

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

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

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