【问题标题】:A Switch Java problem : case expressions must be constant expressions一个 Switch Java 问题:case 表达式必须是常量表达式
【发布时间】:2011-06-12 04:12:54
【问题描述】:

我的 switch/case 语句有问题。错误说:“案例表达式必须是常量表达式”。我理解错误,我可以使用 If 解决它,但有人可以告诉我为什么 case 表达式必须在 switch/case 中保持不变。 我的错误代码示例:

public boolean onOptionsItemSelected(MenuItem item) {
    int idDirectory = ((MenuItem) findViewById(R.id.createDirectory)).getItemId();
    int idSuppression = ((MenuItem) findViewById(R.id.recycleTrash)).getItemId();
    int idSeeTrash = ((MenuItem) findViewById(R.id.seeTrash)).getItemId();

    switch (item.getItemId()) {
    case idDirectory:
        createDirectory(currentDirectory);
        break;
    case idSuppression:
        recycleTrash();
        break;
    case idSeeTrash:
        seeTrash();
        break;
    }

    return super.onOptionsItemSelected(item);
}

谢谢你的解释!!

【问题讨论】:

  • 你为什么使用findViewById().getItemId()?如果你已经有了id,就不需要获取item来获取id!
  • switch 语句不好闻...我建议您考虑使用多态性或适配器模式以获得更好看的代码。此外,您可以完全避免此类问题。
  • @Bnjmn 我同意,特别是当情况经常重复时。如果你很少使用它可能没问题。此外,我有时将它与多态一起使用来创建初始的具体实例。
  • @Bnjmn:由于 Dimitri 使用的是 Android,因此他的 MenuItem 对象很可能在 xml 中定义,并且(据我所知)如果不放弃 MenuInflater.inflate() 的简单性,就不能轻易地对其进行子类化。

标签: java android switch-statement


【解决方案1】:

所以可以在编译阶段进行评估(静态检查)

有关switch 的正式定义,请参阅:http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.11。

此外,它还可以帮助您更好地理解 switch 是如何转换为字节码的:

class Switch {
  void x(int n ) {
    switch( n ) {
      case 1: System.out.println("one"); break;
      case 9: System.out.println("nine"); break;
      default:  System.out.println("nothing"); break;
    }
  }
}

编译后:

C:\>javap -c Switch
Compiled from "Switch.java"
class Switch extends java.lang.Object{
Switch();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

void x(int);
  Code:
   0:   iload_1
   1:   lookupswitch{ //2
                1: 28;
                9: 39;
                default: 50 }
   28:  getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   31:  ldc     #3; //String one
   33:  invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   36:  goto    58
   39:  getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   42:  ldc     #5; //String nine
   44:  invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   47:  goto    58
   50:  getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   53:  ldc     #6; //String nothing
   55:  invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   58:  return

}

看到标记为1:的那一行

 1:   lookupswitch{ //2
            1: 28;
            9: 39;
            default: 50 }

它评估值并转到其他行。例如,如果值为9,它将跳转到指令39:

   39:  getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   42:  ldc     #5; //String nine
   44:  invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   47:  goto    58

然后跳转到指令 58:

   58:  return

如果动态评估,这一切都是不可能的。这就是为什么。

【讨论】:

  • 谢谢,这是一个很好的答案。所以如果用javap编译,我可以看到生成的字节码??
  • @Dimitri。不客气。 javap 是另一个工具(如 javadoc 或 jar ),它是默认的 java dissambler。如果使用-c 调用,您将看到这些说明。
  • 好的。但我在想,你认为在 JVM 中生成的字节码在 Dalvik Machine (Android) 中是否相同。如您所见,我正在开发 Android
  • 其实……不一样。 Dalvik 有自己的代码,但开关在两者中的工作方式相同。好好看看:en.wikipedia.org/wiki/Dalvik_(software)
【解决方案2】:

在 eclipse IDE 中很简单,在 switch 语句中 CTRL + 1 并转换 switch 语句 - if-else 语句http://tools.android.com/tips/non-constant-fields

【讨论】:

    【解决方案3】:

    idDirectory 和其他必须是常量而不是声明的变量。 Switch 在这种情况下不起作用,您需要切换到 if-else 构造。

    编辑 我明白 OP 的意思了。这就是 switch 在 Java 语言中的工作方式。

    【讨论】:

    • 这正是你的问题。如果你不能用常量解决这个问题,只需使用稍微复杂一点的 if-then-else-if-blah-blah 设置。
    • -1 回答 OP 已经知道的内容:我理解错误,我可以使用 If 解决它,但有人可以告诉我为什么 case 表达式必须在 switch/case 中保持不变
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多