Java の switch case ステートメントが整数、short、byte、および character のみを使用し、他のデータ型を使用しないのはなぜですか? どのようなメリットがありますか? 詳しく説明してください。
2 に答える
通常、言語設計に関する質問は、「設計者がそのように決定したため」に要約されます。これはちょうど別の時代です。
しかし、Java には C が起源であり、C も同じことを行いました。80 年代には、コンパイラがスイッチをジャンプ テーブルに変えることができるため、その決定が私に説明されました。基本的に、コードのアドレスの各ブロックは、テーブルと はswitch
範囲チェックになり、その後にアドレスを取得するために渡した値を使用してテーブル ルックアップ (通常は配列または少なくとも配列のリンク リストへのインデックス付け) が行われ、そのアドレスにジャンプします。そのシナリオでは、整数のみが意味を持ちます。コンピューターは常に現在ほど高速ではなかったことに注意してください。C は、コンピューターがはるかに遅かった 60 年代後半の作業に基づいて、70 年代前半に設計されました。
JavaScript など、Java や C と同じ構文上の伝統を持つ一部の言語は、switch
まったく別の書き方を作成if...else/if...else
し、チェックされる型を整数型に制限しません。おそらく、90 年代に設計され、現実的なオプションになったためです。 . あるいは、JavaScript の設計者 (Brendan Eich) がその方法を好んだからかもしれません。
以下で、Baadshahは次のように尋ねます。
好奇心から: それでは、文字列をどのようにサポートするのか ??? アイデアを教えてください。
int
まず、一歩戻ってケースを見てみましょう。
num = Integer.parseInt(args[0]);
switch (num) {
case 1:
System.out.println("You used the special value one");
break;
case 42:
System.out.println("You used the special value forty-two");
break;
case 67:
System.out.println("You used the special value sixty-seven");
break;
default:
System.out.println("You used the a non-special value " + num);
break;
}
次のようなバイトコードが生成されます。
19: iload_2 20: ルックアップスイッチ { // 3 1:56 42:67 67:78 デフォルト: 89 } 56: getstatic #8 // フィールド java/lang/System.out:Ljava/io/PrintStream; 59: ldc #9 // String 特別な値 one を使用しました 61: invokevirtual #10 // メソッド java/io/PrintStream.println:(Ljava/lang/String;)V 64: 後藤114 67: getstatic #8 // フィールド java/lang/System.out:Ljava/io/PrintStream; 70: ldc #11 // String 特別な値である 42 を使用しました 72: invokevirtual #10 // メソッド java/io/PrintStream.println:(Ljava/lang/String;)V 75: 後藤114 78: getstatic #8 // フィールド java/lang/System.out:Ljava/io/PrintStream; 81: ldc #12 // 文字列 特別な値である sixty-seven を使用しました 83: invokevirtual #10 // メソッド java/io/PrintStream.println:(Ljava/lang/String;)V 86: 後藤114 89: getstatic #8 // フィールド java/lang/System.out:Ljava/io/PrintStream; 92: 新しい #13 // クラス java/lang/StringBuilder 95: デュプ 96: invokespecial #14 // メソッド java/lang/StringBuilder."":()V 99: ldc #15 // 文字列 特別ではない値を使用しました 101: invokevirtual #16 // メソッド java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 104: iload_2 105: invokevirtual #17 // メソッド java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 108: invokevirtual #18 // メソッド java/lang/StringBuilder.toString:()Ljava/lang/String; 111: invokevirtual #10 // メソッド java/io/PrintStream.println:(Ljava/lang/String;)V
実際のテーブル ルックアップを確認できますint
。
では、文字列でどのようにそれを行うのですか? 答えの 1 つは、 を構造体にswitch
変換するif...else if...else
ことです。しかし、彼らはそれよりも賢いことをしました: 彼らはハッシュコードを使用して最適化し、equals
衝突から保護するために使用しました:
switch (str) {
case "abc":
System.out.println("You used the special value 'abc'");
break;
case "def":
System.out.println("You used the special value 'def'");
break;
case "ghi":
System.out.println("You used the special value 'ghi'");
break;
default:
System.out.println("You used the a non-special value '" + str + "'");
break;
}
になります:
124:アロード4 126: invokevirtual #19 // メソッド java/lang/String.hashCode:()I 129: ルックアップスイッチ { // 3 96354:164 99333:180 102312:196 デフォルト: 209 } 164: 4 をロード 166: ldc #20 // 文字列 abc 168: invokevirtual #21 // メソッド java/lang/String.equals:(Ljava/lang/Object;)Z 171: イフェク209 174: アイコンスト_0 175: イストア5 177: 後藤 209 180: 4 をロード 182: ldc #22 // 文字列定義 184: invokevirtual #21 // メソッド java/lang/String.equals:(Ljava/lang/Object;)Z 187: イフェク209 190: アイコンスト_1 191: イストア5 193: 後藤209 196: 4 198: ldc #23 // 文字列 ghi 200: invokevirtual #21 // メソッド java/lang/String.equals:(Ljava/lang/Object;)Z 203: イフェク 209 206: アイコンスト_2 207: イストア5 209: ロード5 211: テーブルスイッチ { // 0 ~ 2 0:236 1:247 2:258 デフォルト: 269 } 236: getstatic #8 // フィールド java/lang/System.out:Ljava/io/PrintStream; 239: ldc #24 // String 特別な値 'abc' を使用しました 241: invokevirtual #10 // メソッド java/io/PrintStream.println:(Ljava/lang/String;)V 244: 後藤 299 247: getstatic #8 // フィールド java/lang/System.out:Ljava/io/PrintStream; 250: ldc #25 // String 特別な値 'def' を使用しました 252: invokevirtual #10 // メソッド java/io/PrintStream.println:(Ljava/lang/String;)V 255: 後藤 299 258: getstatic #8 // フィールド java/lang/System.out:Ljava/io/PrintStream; 261: ldc #26 // String 特別な値「ghi」を使用しました 263: invokevirtual #10 // メソッド java/io/PrintStream.println:(Ljava/lang/String;)V 266: 後藤 299 269: getstatic #8 // フィールド java/lang/System.out:Ljava/io/PrintStream; 272: 新しい #13 // クラス java/lang/StringBuilder 275: デュプ 276: invokespecial #14 // メソッド java/lang/StringBuilder."":()V 279: ldc #27 // 文字列 特別ではない値を使用しました ' 281: invokevirtual #16 // メソッド java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 284: アロード_3 285: invokevirtual #16 // メソッド java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 288: ldc #28 // 文字列 ' 290: invokevirtual #16 // メソッド java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 293: invokevirtual #18 // メソッド java/lang/StringBuilder.toString:()Ljava/lang/String; 296: invokevirtual #10 // メソッド java/io/PrintStream.println:(Ljava/lang/String;)V
彼らがそこで何をしたか見てください。現在は基本的に 2 つswitches
です。1 つはハッシュコードに基づいてケースごとに一意の番号を取得し (ただし、 で再確認しますequals
)、2 番目はディスパッチします。