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

Posted

技术标签:

【中文标题】是否可以在 java switch/case 语句中使用类名? [复制]【英文标题】:Is it possible use a class name in java switch/case statement? [duplicate] 【发布时间】:2016-04-09 08:36:13 【问题描述】:

我想使用 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;

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

【问题讨论】:

您可以尝试将字符串分配给最终的 String 局部变量吗? 哪个java版本?在 Java 7/8 上你会得到不同的结果。 @Marged 我正在使用 Java 8,但对任一版本的解决方案都感兴趣... 相关:***.com/q/27955169/1857897 编译时常量表达式的很好解释:***.com/a/3827424/1857897 【参考方案1】:

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

一个可行的解决方案是:

String tableName = "MyClass1";
...
switch (tableName) 
    case "MyClass1":
        return 1;
    case "MyClass2":
        return 2;
    default:
        return Integer.MAX_VALUE;

表达式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;

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

【讨论】:

这对我来说是正确的答案:case 标签必须是常量表达式,类文字和在它们上调用getSimpleName() 的结果都不是常量表达式。 编译时常量表达式的很好的解释可以在这里找到:***.com/a/3827424/1857897 我认为 类文字 是常量表达式,但是 ""+MyClass1.class 应该可以工作,但它没有...... 更反直觉的是enum 常量引用不是编译时常量。它们可以在case 标签和注释中使用,但这是使用规则的例外(尽管不是编译时常量,您也可以在注释中使用类文字)。所以当你说final EnumType X = EnumType.FOO; 时,那么X 将不是编译时常量,也不能用作case 标签(与原始类型和Strings 不同)。底线是只有原始类型和Strings 可以是编译时常量(因为规范是这样说的)。 @MasterJoe2 在 Eclipse 的情况下,它将识别,例如MyClass2.IDENTIFIER 作为MyClass2 的用法。如果您没有源代码,它就不起作用,但仍然不是简单的文本搜索。如果您指的是第一个变体,那么答案中已经描述了这些限制。【参考方案2】:

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

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

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

【讨论】:

我在考虑这个解决方案,但是switch 不是更高效吗? 也许,但您的代码的可读性也会降低,因为您需要为每个类名写一行,然后为每种情况多写几行。您获得的几纳秒优化可能永远不值得使用 Map 获得的代码的清洁度 哦,我忘了补充。如果我没记错的话,字符串上的switches 只是switch on their hashcode,除非最近发生了变化 感谢您的 cmets +1,但我仍然很好奇这个开关是否适合我..【参考方案3】:

为什么不使用 Switch..case 而不是使用 If..Else。在我知道之前应该在所有版本的 java 中工作。

if (tableName.equals(MyClass1.class.getSimpleName())) 
     return 1;
 else if (tableName.equals(MyClass2.class.getSimpleName())) 
     return 2;
 else 
     return Integer.MAX_VALUE;

【讨论】:

我真的不喜欢else if 语句,请参阅@Sam-Sun 的基于Map 的解决方案 由您选择,但直到我知道所有版本都支持此功能,并且您不需要处理任何版本依赖关系。 这个解决方案的问题是,在最坏的情况下,它必须检查每一种可能性,这就是人们想要“切换”的原因。 据我所知,java 中的 switch case 只是 if/then/else 的糖,编译后的代码就是这样。

以上是关于是否可以在 java switch/case 语句中使用类名? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

Java switch case和数组

java中switch case怎么表示范围

Java switch case 语句

Java-Runoob:Java switch case

switch case 支持的 6 种数据类型!

Java switch case语句