2010年9月23日木曜日

JDK7のString in switch

ちょっと前に試してみて、どうやって実現されているか調べたのでメモっておく。
ちゃんと仕様、ソースを見たわけではないので嘘かも知れない。

テストのソースコード
public class Test {
    public static void main(String[] args) {
        String s  = "xyz";
        switch (s) {
        case "abc":
            System.out.println("abc");
            break;
        case "lmn":
            System.out.println("lmn");
            break;
        case "xyz":
            System.out.println("xyz");
            break;
        }
    }
}

javapでバイトコードを出力してみてみたら、分かった気がする。
文字列のhashCodeを得ている
8: invokevirtual #3                  // Method java/lang/String.hashCode:()I
謎の数値でジャンプ先を決めている
11: lookupswitch  { // 3
                   96354: 44
                  107277: 58
                  119193: 72
                 default: 83
            }
追記 - 各文字列のhashCodeを調べた結果
js> java.lang.String("abc").hashCode()
96354
js> java.lang.String("lmn").hashCode()
107277
js> java.lang.String("xyz").hashCode()
119193

これを見る限り、switchする文字列のhashCodeをみて分岐するようだ。
caseの文字列は前もってその文字列のHashCodeに置き換えられて、
整数でのswitch/caseで実現できている。

ただ、ハッシュ値はぶつかることがあるので、
分岐した後本当に正しいかどうかequalsでチェックしてさらに分岐させている。

今回だとabcなら44-55でチェックして0, lmnなら58-69でチェックして1, xyzなら72-82でチェックして2が設定され、
その数字でさらに飛び先が決まる(初期値はiconst_m1/istore_3なので-1) 。
javapの出力(今回不要なところは削った)
{
  public static void main(java.lang.String[]);
    Signature: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    LineNumberTable:
      line 3: 0
      line 4: 3
      line 6: 112
      line 7: 120
      line 9: 123
      line 10: 131
      line 12: 134
      line 15: 142
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
             0     143     0  args   [Ljava/lang/String;
             3     140     1     s   Ljava/lang/String;
    Code:
      stack=2, locals=4, args_size=1
         0: ldc           #2                  // String xyz
         2: astore_1
         3: aload_1
         4: astore_2
         5: iconst_m1
         6: istore_3
         7: aload_2
         8: invokevirtual #3                  // Method java/lang/String.hashCode:()I
        11: lookupswitch  { // 3
                   96354: 44
                  107277: 58
                  119193: 72
                 default: 83
            }
        44: aload_2
        45: ldc           #4                  // String abc
        47: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
        50: ifeq          83
        53: iconst_0
        54: istore_3
        55: goto          83
        58: aload_2
        59: ldc           #6                  // String lmn
        61: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
        64: ifeq          83
        67: iconst_1
        68: istore_3
        69: goto          83
        72: aload_2
        73: ldc           #2                  // String xyz
        75: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
        78: ifeq          83
        81: iconst_2
        82: istore_3
        83: iload_3
        84: tableswitch   { // 0 to 2
                       0: 112
                       1: 123
                       2: 134
                 default: 142
            }
       112: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
       115: ldc           #4                  // String abc
       117: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       120: goto          142
       123: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
       126: ldc           #6                  // String lmn
       128: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       131: goto          142
       134: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
       137: ldc           #2                  // String xyz
       139: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       142: return
}

2010年9月19日日曜日

ブログ移行した

Vox(http://hide-t.vox.com/)からとりあえずbloggerに移行した。
ブログの記事もあんまり書いてないけど、ないと長いの置く場所がないので。

typepadに移して、そこからエクスポート&ツールで変換で終了。
画像もflickrに移行して記事内のリンクはとりあえず直した。
インポートを大量投稿と判定されたせいか、いきなり確認を求められて面倒くさいね。