Java switch语句:需要常量表达式,但它是常量
所以,我正在研究这个类,它有几个静态常数:Java switch语句:需要常量表达式,但它是常量,java,compile-time-constant,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 (co
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个case标签中的每一个上都得到了一个常量表达式required
错误
我知道编译器需要在编译时知道表达式才能编译开关,但是为什么Foo.BA
不是常量呢
我知道编译器需要在编译时知道表达式才能编译开关,但是为什么Foo.BA不是常量呢
虽然从初始化字段后执行的任何代码的角度来看,它们都是常量,但在JLS要求的意义上,它们不是编译时常量;有关常量表达式1的规范,请参阅。这是指定义“常量变量”的变量,如下所示:
我们将原语类型或字符串类型的变量称为常量变量,该变量是最终变量,并用编译时常量表达式(§15.28)初始化。变量是否为常量变量可能涉及到类初始化(§12.4.1)、二进制兼容性(§13.1,§13.4.9)和确定赋值(§16)
在您的示例中,Foo.BA*变量没有初始值设定项,因此不符合“常量变量”的条件。解决方法很简单;将Foo.BA*变量声明更改为具有作为编译时常量表达式的初始值设定项
在其他示例中(初始值设定项已经是编译时常量表达式),可能需要将变量声明为final
您可以将代码更改为使用enum
而不是int
常量,但这会带来另外两个不同的限制:
- 您必须包含一个
大小写,即使对于默认值
的每个已知值都有枚举
;看大小写
标签必须全部是显式的case
值,而不是计算为enum
值的表达式enum
1-常量表达式限制可总结如下。常量表达式a)只能使用原语类型和
字符串,b)只允许原语是文字(除了null
)和常量变量,c)允许常量表达式可能被括在括号中作为子表达式,d)允许除赋值运算符以外的运算符,++
,--
或instanceof
,e)只允许对基元类型或字符串进行类型转换
请注意,这不包括任何形式的方法或lambda调用、new
、.class
.length
或数组订阅。此外,数组值、enum
值、基本包装类型的值、装箱和取消装箱都被排除在外,因为它们不是编译时常量。考虑下面的有效代码:
public static final int BAR = new Random().nextInt();
在运行时,您只能知道条的值。您将获得所需的常量表达式,因为您将这些值从常量中删除。尝试:
public abstract class Foo {
...
public static final int BAR=0;
public static final int BAZ=1;
public static final int BAM=2;
...
}
您可以使用如下示例中所示的枚举:
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;
}
}
}
资料来源:
我建议您使用枚举:)
看看这个:
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());
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
}
我在Android上遇到了这个错误,我的解决方案就是使用:
public static final int TAKE_PICTURE = 1;
而不是
public static int TAKE_PICTURE = 1;
这是很久以前的回答,可能不相关,但只是以防万一。
当我遇到这个问题时,我只使用了if
语句而不是switch
,它解决了错误。
这当然是一个解决办法,可能不是“正确”的解决方案,但在我的情况下,这就足够了
编辑:2021.01.21
这个答案有点误导,我想澄清一下
使用<代码>替换<代码>开关>代码>语句>不应被视为GOTO解决方案,在软件开发中存在“代码>开关/>和<代码>如果两个概念的非常好的原因,以及在两者之间选择时要考虑的性能问题。
虽然我提供了一个解决上述错误的方法,但我的回答并没有阐明问题发生的“原因”,而是提供了解决问题的方法
在我的具体案例中,使用if
语句就足以解决问题。开发人员应该花点时间来决定这是否是当前问题的正确解决方案
因此,在我第一次回答中所述的特定情况下,此答案应仅被视为一种变通方法,而决不是此问题的正确答案有时开关变量也会导致该错误,例如:
switch(view.getTag()) {//which is an Object type
case 0://will give compiler error that says Constant expression required
//...
}
要解决此问题,应将变量强制转换为int(在本例中)。因此:
在Android中执行以下操作时出现此错误:
System.out.println(Foo.BAR.getDescription());
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
}
就我而言,我得到这个例外是因为
switch (tipoWebServ) {
case VariablesKmDialog.OBTENER_KM:
resultObtenerKm(result);
break;
case var.MODIFICAR_KM:
resultModificarKm(result);
break;
}
在第二种情况下,我从实例var.MODIFICAR_KM:
调用常量,但我应该直接从类中使用VariablesKmDialog.OBTENER_KM
。如果在开关情况下使用它,那么即使在将该值插入开关之前,也需要获取枚举的类型。例如:
SomeEnum SomeEnum=SomeEnum.values()[1]
枚举如下所示:
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;
}
}
下面的代码是不言自明的,
我们可以将枚举与开关案例一起使用:
/**
*
*/
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;
}
希望有帮助:)我建议使用以下方法:
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;
}
}
}
有趣。public static final int BAR=new Random().nextInt()
有效吗?Thilo的语句可以编译,但switch语句需要常量表达式。此外,两个连续的new Random().nextInt()
不能返回相同的值吗?@Tony:这是一件好事。它不是c
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;
}
}
}