为什么我不能在String上使用switch语句? [英] Why can't I use switch statement on a String?




Is this functionality going to be put into a later Java version?


Can someone explain why I can't do this, as in, the technical way Java's switch statement works?


切换语句字符串案例已在 Java SE 7 中实施,至少16年首次申请后。明确的延迟原因没有提供,但它可能与性能有关。

Switch statements with String cases have been implemented in Java SE 7, at least 16 years after they were first requested. A clear reason for the delay was not provided, but it likely had to do with performance.

该功能有现已在 javac 以使用字符串 案例声明中的常量,使用process; 一个干净的高级语法在编译时将x扩展为遵循模式的更复杂的代码。生成的代码使用始终存在的JVM指令。

The feature has now been implemented in javac with a "de-sugaring" process; a clean, high-level syntax using String constants in case declarations is expanded at compile-time into more complex code following a pattern. The resulting code uses JVM instructions that have always existed.

一个开关,带有 String 在编译期间将案例转换为两个开关。第一个将每个字符串映射到一个唯一的整数—它在原始开关中的位置。这是通过首先打开标签的哈希码来完成的。相应的情况是 if 语句测试字符串相等性;如果哈希上有冲突,则测试是级联的 if-else-if 。第二个开关镜像原始源代码中的那个,但用它们对应的位置替换案例标签。这个两步过程可以很容易地保留原始开关的流量控制。

A switch with String cases is translated into two switches during compilation. 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 there are collisions on the hash, the test is a cascading 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.

有关开关的更多技术深度,您可以参考JVM规范,其中 switch语句的编译。简而言之,有两种不同的JVM指令可用于交换机,具体取决于案例使用的常量的稀疏性。两者都依赖于使用整数常量来有效执行每种情况。

For more technical depth on switch, you can refer to the JVM Specification, where the compilation of switch statements is described. 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. Both depend on using integer constants for each case to execute efficiently.

如果常量是密集的,它们将被用作索引(在减去最低值之后)到指令指针表中— tableswitch 指令。

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.

如果常量稀疏,则执行正确情况的二进制搜索— lookupswitch 指令。

If the constants are sparse, a binary search for the correct case is performed—the lookupswitch instruction.

String 对象上取消开关 ,两种说明都可能被使用。 lookupswitch 适用于哈希码的第一次切换,以查找案例的原始位置。生成的序数非常适合 tableswitch

In de-sugaring a switch on String objects, both instructions are likely to be used. The lookupswitch is suitable for the first switch on hash codes to find the original position of the case. The resulting ordinal is a natural fit for a tableswitch.

这两个指令都需要为每个案例分配的整数常量在编译时排序。在运行时, O(1) tableswitch 的性能通常优于 O (log(n)) lookupswitch 的性能,它需要一些分析来确定表是否足够密集以证明空间–时间权衡。 Bill Venners写了一篇很棒的文章,更详细地介绍了这一点,同时还有一篇文章。 - 查看其他Java流控制指令。

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. 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.

在JDK 7之前, enum 可以接近基于 String 的开关。这使用静态 valueOf 方法由编译器在每个枚举类型上生成。例如:

Prior to JDK 7, enum could approximate a String-based switch. This uses the static valueOf method generated by the compiler on every enum type. For example:

Pill p = Pill.valueOf(str);
switch(p) {
  case RED:  pop();  break;
  case BLUE: push(); break;


登录 关闭
发送“验证码”获取 | 15天全站免登陆