gpt4 book ai didi

java - 为什么switch on String会编译成两个switch

转载 作者:IT老高 更新时间:2023-10-28 21:01:56 25 4
gpt4 key购买 nike

我读过 JVM specification关于编译开关,并对如何编译 String 上的 switch 语句产生了兴趣。这是我检查的测试方法(JDK1.7.0_40):

static int test(String i) {
switch (i) {
case "a": return -100;
case "45b": return 1;
case "c": return 2;
default: return -1;
}
}

我希望这个方法被编译成简单的lookupswitch on hashCode的字符串,但是突然

static int test(java.lang.String);
Code:
0: aload_0
1: astore_1
2: iconst_m1
3: istore_2
4: aload_1
5: invokevirtual #6 // Method java/lang/String.hashCode:()I
8: lookupswitch { // 3
97: 44
99: 72
51713: 58
default: 83
}
44: aload_1
45: ldc #7 // String a
47: invokevirtual #8 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
50: ifeq 83
53: iconst_0
54: istore_2
55: goto 83
58: aload_1
59: ldc #9 // String 45b
61: invokevirtual #8 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
64: ifeq 83
67: iconst_1
68: istore_2
69: goto 83
72: aload_1
73: ldc #10 // String c
75: invokevirtual #8 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
78: ifeq 83
81: iconst_2
82: istore_2
83: iload_2
84: tableswitch { // 0 to 2
0: 112
1: 115
2: 117
default: 119
}
112: bipush -100
114: ireturn
115: iconst_1
116: ireturn
117: iconst_2
118: ireturn
119: iconst_m1
120: ireturn

如您所见,在第一个 lookupswitch 的分支中,JVM 并没有真正为后续的 tableswitch(第 84 行)生成索引。
Tableswitch 应该工作得很快,所以不会带来很多额外的工作。但是不管怎样,生成额外的开关的目的是什么?
更新
我了解 hashCode 冲突的可能性。我想说的是,编译器可以将所有实际工作从后续 tableswitch 移到 first,然后使用 ifeq 跳转到所有 switch 分支的末尾,而不是后续的 tableswitch。 所以我在这里看到的一个可能的答案是:在第一个 switch 编译器中,它尝试根据已知数量的情况为 ifeq 跳转预先计算标签,但我不确定这是唯一的原因。

更新2
正如 @ericbn 所建议的,我尝试编译

switch (i) { 
case 97: return -100;
case 51713: return 1;
case 99: return 2;
default: return -1;
}

将 i 作为 int,编译器给了我简单的查找开关。

最佳答案

引自 javac source code :

         * The general approach used is to translate a single
* string switch statement into a series of two chained
* switch statements: the first a synthesized statement
* switching on the argument string's hash value and
* computing a string's position in the list of original
* case labels, if any, followed by a second switch on the
* computed integer value. The second switch has the same
* code structure as the original string switch statement
* except that the string case labels are replaced with
* positional integer constants starting at 0.
*
* The first switch statement can be thought of as an
* inlined map from strings to their position in the case
* label list. An alternate implementation would use an
* actual Map for this purpose, as done for enum switches.
*
* With some additional effort, it would be possible to
* use a single switch statement on the hash code of the
* argument, but care would need to be taken to preserve
* the proper control flow in the presence of hash
* collisions and other complications, such as
* fallthroughs. Switch statements with one or two
* alternatives could also be specially translated into
* if-then statements to omit the computation of the hash
* code.

关于java - 为什么switch on String会编译成两个switch,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25568639/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com