java 编译开关_java – 字符串是关于开关的数字类型,并始终编译为lookupswitch?
以下代碼返回給定的String s是否等于任何其他硬編碼字符串.該方法使用switch語(yǔ)句來(lái)執(zhí)行此操作:
public class SwitchOnString {
public static boolean equalsAny(String s) {
switch (s) {
case "string 1":
return true;
case "string 2":
return true;
default:
return false;
}
}
}
Compilation of switch statements uses the tableswitch and lookupswitch
instructions.
此外
tableswitch and lookupswitch instructions operate only on int data.
我閱讀了3.10章,但沒(méi)有找到提到的String.
間接關(guān)閉的唯一一句是:
Other numeric types must be narrowed to type int for use in a switch.
問(wèn)題1:
此上下文中的String也是數(shù)字類型嗎?還是我錯(cuò)過(guò)了什么?
SwitchOnString類上的javap -c顯示:
Compiled from "SwitchOnString.java"
public class playground.SwitchOnString {
public playground.SwitchOnString();
...
public static boolean equalsAny(java.lang.String);
Code:
0: aload_0
1: dup
2: astore_1
3: invokevirtual #16 // Method java/lang/String.hashCode:()I
6: lookupswitch { // 2
1117855161: 32
1117855162: 44
default: 60
}
...
}
顯然,hashCode值用作case的int-keys.這可能匹配:
The lookupswitch instruction pairs int keys (the values of the case
labels) …
繼續(xù)使用tableswitch和lookupswitch JMS說(shuō):
The tableswitch instruction is used when the cases of the switch can
be efficiently represented as indices into a table of target offsets. (…)
Where the cases of the switch are sparse, the table representation of
the tableswitch instruction becomes inefficient in terms of space. The
lookupswitch instruction may be used instead.
如果我做到了這一點(diǎn),那么案例越稀疏,查找切換的可能性就越大.
問(wèn)題2:
但是看一下字節(jié)碼:
兩個(gè)字符串大小是否足夠稀疏以編譯切換到lookupswitch?或者將String上的每個(gè)開關(guān)編譯為lookupswitch?
最佳答案 規(guī)范沒(méi)有說(shuō)明如何編譯switch語(yǔ)句,這取決于編譯器.
在這方面,JVMS語(yǔ)句“其他數(shù)字類型必須縮小到int類型才能在交換機(jī)中使用”并不是說(shuō)Java編程語(yǔ)言會(huì)進(jìn)行這樣的轉(zhuǎn)換,也不會(huì)說(shuō)String或Enum是數(shù)字類型.即long,float和double是數(shù)字類型,但是不支持在Java編程語(yǔ)言中將它們與switch語(yǔ)句一起使用.
所以語(yǔ)言規(guī)范說(shuō)支持切換字符串,因此,編譯器必須找到一種方法將它們編譯為字節(jié)碼.使用像哈希碼這樣的不變屬性是一種常見(jiàn)的解決方案,但原則上,也可以使用其他屬性,如長(zhǎng)度或任意字符.
然后,編譯器必須選擇lookupswitch或tableswitch指令.當(dāng)數(shù)字不稀疏時(shí),javac確實(shí)使用tableswitch,但僅當(dāng)語(yǔ)句具有兩個(gè)以上的case標(biāo)簽時(shí)才使用.
所以當(dāng)我編譯以下方法時(shí):
public static char two(String s) {
switch(s) {
case "a": return 'a';
case "b": return 'b';
}
return 0;
}
我明白了
public static char two(java.lang.String);
Code:
0: aload_0
1: astore_1
2: iconst_m1
3: istore_2
4: aload_1
5: invokevirtual #9 // Method java/lang/String.hashCode:()I
8: lookupswitch { // 2
97: 36
98: 50
default: 61
}
36: aload_1
37: ldc #10 // String a
39: invokevirtual #11 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
42: ifeq 61
45: iconst_0
46: istore_2
47: goto 61
50: aload_1
51: ldc #12 // String b
53: invokevirtual #11 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
56: ifeq 61
59: iconst_1
60: istore_2
61: iload_2
62: lookupswitch { // 2
0: 88
1: 91
default: 94
}
88: bipush 97
90: ireturn
91: bipush 98
93: ireturn
94: iconst_0
95: ireturn
但是當(dāng)我編譯時(shí),
public static char three(String s) {
switch(s) {
case "a": return 'a';
case "b": return 'b';
case "c": return 'c';
}
return 0;
}
我明白了
public static char three(java.lang.String);
Code:
0: aload_0
1: astore_1
2: iconst_m1
3: istore_2
4: aload_1
5: invokevirtual #9 // Method java/lang/String.hashCode:()I
8: tableswitch { // 97 to 99
97: 36
98: 50
99: 64
default: 75
}
36: aload_1
37: ldc #10 // String a
39: invokevirtual #11 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
42: ifeq 75
45: iconst_0
46: istore_2
47: goto 75
50: aload_1
51: ldc #12 // String b
53: invokevirtual #11 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
56: ifeq 75
59: iconst_1
60: istore_2
61: goto 75
64: aload_1
65: ldc #13 // String c
67: invokevirtual #11 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
70: ifeq 75
73: iconst_2
74: istore_2
75: iload_2
76: tableswitch { // 0 to 2
0: 104
1: 107
2: 110
default: 113
}
104: bipush 97
106: ireturn
107: bipush 98
109: ireturn
110: bipush 99
112: ireturn
113: iconst_0
114: ireturn
目前還不清楚為什么javac做出這個(gè)選擇.雖然tableswitch與lookupswitch相比具有更高的基本占用空間(一個(gè)額外的32位字),但在字節(jié)碼中它仍然會(huì)更短,即使對(duì)于兩個(gè)案例標(biāo)簽場(chǎng)景也是如此.
但是決策的一致性可以用第二個(gè)語(yǔ)句顯示,它將始終具有相同的值范圍,但僅根據(jù)標(biāo)簽的數(shù)量編譯為lookupswitch或tableswitch.因此,當(dāng)使用真正的稀疏值時(shí):
public static char three(String s) {
switch(s) {
case "a": return 'a';
case "b": return 'b';
case "": return 0;
}
return 0;
}
它編譯成
public static char three(java.lang.String);
Code:
0: aload_0
1: astore_1
2: iconst_m1
3: istore_2
4: aload_1
5: invokevirtual #9 // Method java/lang/String.hashCode:()I
8: lookupswitch { // 3
0: 72
97: 44
98: 58
default: 83
}
44: aload_1
45: ldc #10 // String a
47: invokevirtual #11 // 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 #12 // String b
61: invokevirtual #11 // 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 #13 // String
75: invokevirtual #11 // 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: 118
default: 120
}
112: bipush 97
114: ireturn
115: bipush 98
117: ireturn
118: iconst_0
119: ireturn
120: iconst_0
121: ireturn
使用lookupswitch作為稀疏哈希碼,但使用tableswitch作為第二個(gè)交換機(jī).
總結(jié)
以上是生活随笔為你收集整理的java 编译开关_java – 字符串是关于开关的数字类型,并始终编译为lookupswitch?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java c3p0 配置文件_关于最近一
- 下一篇: php计算时间差js,JavaScrip