web-dev-qa-db-ja.com

Javaのswitchステートメントのデータ型を長くできないのはなぜですか?

SunのJavaチュートリアル からの抜粋です:

スイッチは、byteshortchar、およびintプリミティブデータ型で動作します。また、列挙型(クラスと継承で説明)および特定のプリミティブ型を「ラップ」するいくつかの特別なクラスCharacterByteShort、およびInteger(シンプルデータオブジェクトで説明)。

longプリミティブデータ型が許可されない正当な理由がなければなりません。誰もがそれを知っていますか?

74
Fostah

スイッチの一般的な使用法に基づいた、おそらくはarbitrary意的な決定だと思います。

スイッチは、基本的に2つの方法(または原則として、組み合わせ)で実装できます。少数のケース、または値が広く分散しているケースでは、スイッチは基本的に一時変数の一連のifと同等になります(スイッチオンされる値は一度だけ評価される必要があります)。値が多かれ少なかれ連続する中程度の数のケースでは、切り替えテーブル(JavaのTABLESWITCH命令)が使用されます。これにより、ジャンプ先がテーブルで効果的に検索されます。

これらのメソッドのいずれも、原則として整数ではなく長い値を使用できます。しかし、命令セットとコンパイラの複雑さと実際のニーズとのバランスをとることは、おそらく実際的な決定だったと思います:本当に長い間切り替える必要がある場合は、まれに書き直さなければならないので十分です一連のIFステートメント、または他の方法で処理します(問題の長い値が互いに近い場合は、Javaコードで、最小値を減算したint結果を切り替えることができます)。

46
Neil Coffey

彼らはバイトコードに必要な命令を実装しておらず、あなたは実際に多くのケースを書きたくないのです。あなたのコードは...

[編集:この回答のコメントから抽出し、背景にいくつか追加します]

正確に言うと、2³²はlotのケースであり、それ以上の長さを保持するのに十分な長さのメソッドを持つプログラムはまったく恐ろしいことです!どの言語でも。 (どの言語のコードでも私が知っている最長の関数は、6k SLOCを少し上回っています。はい、それはswitchであり、本当に管理できません。)longにはint以下のみが必要ですが、2つの選択肢があります。

  1. ハッシュ関数をテーマにしたバリアントを使用して、longintに圧縮します。型が間違っている場合にのみ使用する最も単純な方法は、キャストすることです!より便利な方法は次のとおりです。

    (int) ((x&0xFFFFFFFF) ^ ((x >>> 32) & 0xFFFFFFFF))
    

    結果をオンにする前に。テスト対象のケースも変換する方法を考え出す必要があります。しかし実際には、多くの場合の実際の問題に対処していないため、それは依然として恐ろしいことです。

  2. 非常に多くのケースで作業している場合のより良い解決策は、Map<Long,Runnable>または同様のものを使用して、特定の値をディスパッチする方法を調べます。これにより、ケースを複数のファイルに分けることができます。これは、関連する実装クラスのホストの登録を整理するのがより複雑になりますが、ケースカウントが大きくなると管理がはるかに容易になります。登録コードを自動的に作成します)。

    FWIW、私はこれを何年も前に行いました(プロジェクトの途中で新しくリリースされたJ2SE 1.2に切り替えました)超並列ハードウェアをシミュレートするためのカスタムバイトコードエンジンを構築するとき(いいえ、JVMの再利用は根本的な理由で適切ではなかったでしょう)さまざまな値と実行モデルが含まれます)、Cバージョンのコードが使用していた大きなswitchに比べてコードを大幅に簡素化しました。

持ち帰りメッセージを繰り返しますが、switchlongにしたいということは、プログラムの型が間違っているか、それだけのシステムを構築していることを示しています。クラスを使用する必要があることを含むバリエーション。どちらの場合でも再考の時間です。

19
Donal Fellows

ルックアップテーブルインデックスは32ビットでなければならないためです。

4
JRL