为什么我不能在String上使用switch语句?
为什么我不能在String上使用switch语句?
这个功能会在以后的Java版本中添加吗?
有人可以解释一下为什么我不能这样做,也就是Java的switch
语句如何运作的技术方法吗?
\n\n如果你的代码中有一个可以根据一个字符串进行切换的地方,那么重构这个字符串为可能的枚举值可能会更好,这样你可以将其用作切换条件。当然,你需要将可能的字符串值限制为枚举中的值,这可能是需要或不需要的。当然,你的枚举可以有一个\'其他\'的条目,并且有一个fromString(String)方法,然后你就可以有
ValueEnum enumval = ValueEnum.fromString(myString); switch (enumval) { case MILK: lap(); break; case WATER: sip(); break; case BEER: quaff(); break; case OTHER: default: dance(); break; }
。
String
类型的switch语句已经在Java SE 7中实现,这至少是在第一次请求之后的16年。没有明确的延迟原因,但这可能与性能有关。
JDK 7中的实现
现在,这个功能已经在javac
中实现了一个“去糖化”过程;在case
声明中使用String
常量的干净高级语法会在编译时扩展为遵循模式的更复杂的代码。生成的代码使用JVM指令,这些指令一直存在。
带有String
case的switch
在编译时被翻译为两个switch。第一个将每个字符串映射到唯一的整数 - 它在原始switch中的位置。这是通过首先切换标签的哈希码来完成的。相应的case是一个测试字符串相等的if
语句;如果哈希上有碰撞,则测试是一个级联的if-else-if
。第二个switch反映了原始源代码中的switch,但用其对应的位置替换了case标签。这个两步过程使得很容易保留原始switch的流程控制。
JVM中的switch
有关switch
的更多技术深度,您可以参考JVM规范,在其中描述了switch
语句的编译。简而言之,取决于case
使用的常量的稀疏程度,有两种不同的JVM指令可用于switch。两者都依赖于使用每个case的整数常量以有效地执行。
如果常量是密集的,则将它们用作索引(减去最低值后)到指令指针表中——tableswitch
指令。
如果常量是稀疏的,则执行针对正确情况的二分查找——lookupswitch
指令。
在对String
对象执行switch
时,这两个指令都可能会被使用。对于第一个在哈希码上的switch来找到原始位置,使用lookupswitch
是适合的。得到的序数自然适合作为tableswitch
。
这两个指令都要求在编译时对每个case分配的整数常量进行排序。在运行时,虽然tableswitch
的O(1)
性能通常优于lookupswitch
的O(log(n))
性能,但需要进行一些分析以确定表是否足够密集以证明空间-时间的权衡。Bill Venners撰写了一篇名为“优化Java代码中'switch'语句的性能”的精彩文章,其中详细介绍了这一点,以及其他Java流控制指令的底层实现。
JDK 7之前
JDK 7之前,enum
可以近似于基于String
的switch。这使用编译器在每个enum
类型上生成的静态valueOf
方法。例如:
Pill p = Pill.valueOf(str); switch(p) { case RED: pop(); break; case BLUE: push(); break; }