Java 7で導入されたJSR 334には、「Strings in switch」がありますが、switch構文でString型も扱えるようになっています。それがどのようにコンパイルされるのかを調べてみました。
package a;
public class E {
public static int a(String s){
switch(s){
case "a":
return 1;
case "b":
return 2;
default:
return 3;
}
}
}
上記ソースをjavacでコンパイルして、javap -verboseしてみました。
Classfile /E:/tmp/java/java7/bin/a/E.class
Last modified 2011/09/23; size 491 bytes
MD5 checksum 525f1ebe51742f599543582cb206c23c
Compiled from "E.java"
public class a.E
SourceFile: "E.java"
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #7.#18 // java/lang/Object."<init>":()V
#2 = Methodref #19.#20 // java/lang/String.hashCode:()I
#3 = String #12 // a
#4 = Methodref #19.#21 // java/lang/String.equals:(Ljava/lang/Object;)Z
#5 = String #22 // b
#6 = Class #23 // a/E
#7 = Class #24 // java/lang/Object
#8 = Utf8 <init>
#9 = Utf8 ()V
#10 = Utf8 Code
#11 = Utf8 LineNumberTable
#12 = Utf8 a
#13 = Utf8 (Ljava/lang/String;)I
#14 = Utf8 StackMapTable
#15 = Class #25 // java/lang/String
#16 = Utf8 SourceFile
#17 = Utf8 E.java
#18 = NameAndType #8:#9 // "<init>":()V
#19 = Class #25 // java/lang/String
#20 = NameAndType #26:#27 // hashCode:()I
#21 = NameAndType #28:#29 // equals:(Ljava/lang/Object;)Z
#22 = Utf8 b
#23 = Utf8 a/E
#24 = Utf8 java/lang/Object
#25 = Utf8 java/lang/String
#26 = Utf8 hashCode
#27 = Utf8 ()I
#28 = Utf8 equals
#29 = Utf8 (Ljava/lang/Object;)Z
{
public a.E();
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
public static int a(java.lang.String);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: aload_0
1: astore_1
2: iconst_m1
3: istore_2
4: aload_1
5: invokevirtual #2 // Method java/lang/String.hashCode:()I
8: lookupswitch { // 2
97: 36
98: 50
default: 61
}
36: aload_1
37: ldc #3 // String a
39: invokevirtual #4 // 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 #5 // String b
53: invokevirtual #4 // 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: 90
default: 92
}
88: iconst_1
89: ireturn
90: iconst_2
91: ireturn
92: iconst_3
93: ireturn
LineNumberTable:
line 5: 0
line 7: 88
line 9: 90
line 11: 92
StackMapTable: number_of_entries = 6
frame_type = 253 /* append */
offset_delta = 36
locals = [ class java/lang/String, int ]
frame_type = 13 /* same */
frame_type = 10 /* same */
frame_type = 26 /* same */
frame_type = 1 /* same */
frame_type = 1 /* same */
}
案の定ハッシュ値を使っていて、次のような流れで処理していることが判ります。
- ローカル変数2を-1で初期化し(60~61行目)、
- 引数のString型のハッシュ値を取得し(63行目)、
- 1つ目のlookupswitchでハッシュ値が同値なら、さらにString.equals()で評価し(64~84行目)、
- 評価結果をローカル変数2に数値を代入して(0または1)(75、76、82、83行目)、
- 2つ目のlookupswitchで、ローカル変数2の値に応じた処理を行う(84~97行目)
2つのlookupswitchを使って条件分岐しているのは意外でした。
0 件のコメント:
コメントを投稿