java 编译开关_java – 字符串是关于开关的数字类型,并始终编译为lookupswitch?
以下代碼返回給定的String s是否等于任何其他硬編碼字符串.該方法使用switch語句來執行此操作:
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章,但沒有找到提到的String.
間接關閉的唯一一句是:
Other numeric types must be narrowed to type int for use in a switch.
問題1:
此上下文中的String也是數字類型嗎?還是我錯過了什么?
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) …
繼續使用tableswitch和lookupswitch JMS說:
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.
如果我做到了這一點,那么案例越稀疏,查找切換的可能性就越大.
問題2:
但是看一下字節碼:
兩個字符串大小是否足夠稀疏以編譯切換到lookupswitch?或者將String上的每個開關編譯為lookupswitch?
最佳答案 規范沒有說明如何編譯switch語句,這取決于編譯器.
在這方面,JVMS語句“其他數字類型必須縮小到int類型才能在交換機中使用”并不是說Java編程語言會進行這樣的轉換,也不會說String或Enum是數字類型.即long,float和double是數字類型,但是不支持在Java編程語言中將它們與switch語句一起使用.
所以語言規范說支持切換字符串,因此,編譯器必須找到一種方法將它們編譯為字節碼.使用像哈希碼這樣的不變屬性是一種常見的解決方案,但原則上,也可以使用其他屬性,如長度或任意字符.
然后,編譯器必須選擇lookupswitch或tableswitch指令.當數字不稀疏時,javac確實使用tableswitch,但僅當語句具有兩個以上的case標簽時才使用.
所以當我編譯以下方法時:
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
但是當我編譯時,
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做出這個選擇.雖然tableswitch與lookupswitch相比具有更高的基本占用空間(一個額外的32位字),但在字節碼中它仍然會更短,即使對于兩個案例標簽場景也是如此.
但是決策的一致性可以用第二個語句顯示,它將始終具有相同的值范圍,但僅根據標簽的數量編譯為lookupswitch或tableswitch.因此,當使用真正的稀疏值時:
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作為第二個交換機.
總結
以上是生活随笔為你收集整理的java 编译开关_java – 字符串是关于开关的数字类型,并始终编译为lookupswitch?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java c3p0 配置文件_关于最近一
- 下一篇: centos java 集成环境搭建,C