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 番目はディスパッチします。