是否可以在java switch/case语句中使用类名?

ded*_*dek 16 java final const class-names switch-statement

我想使用一个java switch语句,它使用class名称作为case常量.有可能吗?或者我是否必须复制类名?

由于编译器错误,以下代码不起作用:

case表达式必须是常量表达式

String tableName = "MyClass1";

...

switch (tableName) {
case MyClass1.class.getSimpleName():
    return 1;
case MyClass2.class.getSimpleName():
    return 2;
default:
    return Integer.MAX_VALUE;
}
Run Code Online (Sandbox Code Playgroud)

以下是该问题的在线演示(openjdk 1.8.0_45):http://goo.gl/KvsR6u

Hol*_*ger 9

编译器错误已经说明了.案例标签必须是常量表达式,类文字和调用getSimpleName()它们的结果都不是常量表达式.

一个有效的解决方案是:

String tableName = "MyClass1";
...
switch (tableName) {
    case "MyClass1":
        return 1;
    case "MyClass2":
        return 2;
    default:
        return Integer.MAX_VALUE;
}
Run Code Online (Sandbox Code Playgroud)

表达式MyClass1.class.getSimpleName()并不比简单"MyClass1",但是,当然,不会有任何编译时检查名称是否与现有类匹配,重构工具或混淆器不会注意到类MyClass1和字符串文字之间的关系"MyClass1".

没有解决方案.您可以做的唯一减少问题的方法是声明关联类中的键以记录关系,例如

class MyClass1 {
    static final String IDENTIFIER = "MyClass1";
    ...
}
class MyClass2 {
    static final String IDENTIFIER = "MyClass2";
    ...
}
...
String tableName = MyClass1.IDENTIFIER;
...
switch (tableName) {
    case MyClass1.IDENTIFIER:
        return 1;
    case MyClass2.IDENTIFIER:
        return 2;
    default:
        return Integer.MAX_VALUE;
}
Run Code Online (Sandbox Code Playgroud)

这记录了与读者的关系,但工具仍然不能确保实际的字符串内容与类名匹配.但是,根据您想要实现的目标,现在可能变得无关紧要,字符串内容是否与类名相匹配......

  • @MasterJoe2 在 Eclipse 的情况下,它将识别,例如“MyClass2.IDENTIFIER”作为“MyClass2”的用法。如果您没有源代码,它就不起作用,但仍然不是一个简单的文本搜索。如果您指的是第一个变体,则答案中已经描述了限制。 (3认同)
  • 更违反直觉的是,`enum` 常量引用不是编译时常量。不过,它们可以用在“case”标签和注释中,但这是使用规则的例外(您也可以在注释中使用类文字,尽管它们不是编译时常量)。所以当你说 `final EnumType X = EnumType.FOO;` 时,`X` 将不是一个编译时常量并且不能用作 `case` 标签(与原始类型和 `String`s 不同)。底线是只有原始类型和 `String`s 可以是编译时常量(因为规范是这样说的)。 (2认同)

Sam*_*Sun 8

为什么不将映射存储在地图中而不是使用开关?

创建String to Integer的映射,并将所有类名映射到它们的返回值.

在请求中,如果条目不存在,则返回默认值.否则,返回地图中的值.

  • 也许,但是你的代码也会变得不那么可读,因为你需要为每个类名称添加一行,然后为每种情况添加一些代码.你得到的几纳秒的优化可能永远不值得使用`Map`来获得代码的清晰度 (2认同)