所以,我正在研究这个有一些静态常量的类:
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_
不是常量?
答案 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
常量,但这会带来另外两种不同的限制:
default
个案,即使您case
的每个已知值都有enum
;见Why is default required for a switch on an enum? case
标签必须全部为显式enum
值,而不是评估为enum
值的表达式。 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;
}
}
}
答案 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());