Switch statements with String
cases have been implemented in Java SE 7 , at least 16 years after they were first requested.
(带有String
switch语句已在Java SE 7中实现 ,至少在首次提出要求后的 16年。)
A clear reason for the delay was not provided, but it likely had to do with performance. (没有提供延迟的明确原因,但可能与性能有关。)
Implementation in JDK 7 (在JDK 7中实现)
The feature has now been implemented in javac
with a "de-sugaring" process;
(现在,该功能已通过javac
中的“反糖化”过程实现。)
a clean, high-level syntax using String
constants in case
declarations is expanded at compile-time into more complex code following a pattern. (在case
声明中使用String
常量的一种干净的高级语法在编译时扩展为遵循模式的更复杂的代码。)
The resulting code uses JVM instructions that have always existed. (生成的代码使用始终存在的JVM指令。)
A switch
with String
cases is translated into two switches during compilation.
(在编译过程中,具有String
的switch
将转换为两个开关。)
The first maps each string to a unique integer—its position in the original switch. (第一个将每个字符串映射到一个唯一的整数-它在原始开关中的位置。)
This is done by first switching on the hash code of the label. (这是通过首先打开标签的哈希码来完成的。)
The corresponding case is an if
statement that tests string equality; (相应的情况是一个if
语句,用于测试字符串是否相等;)
if there are collisions on the hash, the test is a cascading if-else-if
. (如果哈希上有冲突,则测试为级联的if-else-if
。)
The second switch mirrors that in the original source code, but substitutes the case labels with their corresponding positions. (第二个开关在原始源代码中进行镜像,但是用相应的位置替换了大小写标签。)
This two-step process makes it easy to preserve the flow control of the original switch. (此两步过程使保留原始交换机的流量控制变得容易。)
Switches in the JVM (在JVM中切换)
For more technical depth on switch
, you can refer to the JVM Specification, where the compilation of switch statements is described.
(有关switch
更多技术深度,可以参考JVM规范,其中描述了switch语句的编译 。)
In a nutshell, there are two different JVM instructions that can be used for a switch, depending on the sparsity of the constants used by the cases. (简而言之,有两种不同的JVM指令可用于切换,具体取决于案例使用的常量的稀疏性。)
Both depend on using integer constants for each case to execute efficiently. (两者都依赖于每种情况下使用整数常量来有效执行。)
If the constants are dense, they are used as an index (after subtracting the lowest value) into a table of instruction pointers—the tableswitch
instruction.
(如果常量是密集的,则将它们用作指令指针表( tableswitch
指令)的索引(减去最小值后)。)
If the constants are sparse, a binary search for the correct case is performed—the lookupswitch
instruction.
(如果常量稀疏,则执行二进制搜索以lookupswitch
正确的大小写lookupswitch
指令。)
In de-sugaring a switch
on String
objects, both instructions are likely to be used.
(在对String
对象的switch
进行除糖处理时,很可能会使用这两个指令。)
The lookupswitch
is suitable for the first switch on hash codes to find the original position of the case. (lookupswitch
适用于哈希码的第一个开关,以查找案例的原始位置。)
The resulting ordinal is a natural fit for a tableswitch
. (产生的序数自然适用于tableswitch
。)
Both instructions require the integer constants assigned to each case to be sorted at compile time.
(两条指令都要求在编译时对分配给每种情况的整数常量进行排序。)
At runtime, while the O(1)
performance of tableswitch
generally appears better than the O(log(n))
performance of lookupswitch
, it requires some analysis to determine whether the table is dense enough to justify the space–time tradeoff. (在运行时,而O(1)
性能tableswitch
一般都比较好显得比O(log(n))
的性能lookupswitch
,它需要一些分析,以确定该表是否是密集足以证明时空权衡。)
Bill Venners wrote a great article that covers this in more detail, along with an under-the-hood look at other Java flow control instructions. (Bill Venners写了一篇很棒的文章 ,其中更详细地介绍了此内容,同时还深入介绍了其他Java流程控制指令。)
Before JDK 7 (在JDK 7之前)
Prior to JDK 7, enum
could approximate a String
-based switch.
(在JDK 7之前, enum
可以近似于基于String
的开关。)
This uses the static valueOf
method generated by the compiler on every enum
type. (这将使用编译器针对每种enum
类型生成的静态valueOf
方法。)
For example: (例如:)
Pill p = Pill.valueOf(str);
switch(p) {
case RED: pop(); break;
case BLUE: push(); break;
}