10

Java の switch case ステートメントが整数、short、byte、および character のみを使用し、他のデータ型を使用しないのはなぜですか? どのようなメリットがありますか? 詳しく説明してください。

4

2 に答える 2

16

通常、言語設計に関する質問は、「設計者がそのように決定したため」に要約されます。これはちょうど別の時代です。

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

于 2013-06-07T04:39:21.657 に答える