20

私はJava言語仕様、第3版を読んでいて、仕様とjavacコンパイラの実装との間の不一致であると私が思うものを見つけました。同じ不一致がEclipseコンパイラーにも存在します。

セクション15.16では、キャスト式について説明しています。引数タイプをキャスト変換(セクション5.5)でキャストタイプに変換できない場合は、コンパイル時エラーになるはずです。

オペランドのコンパイル時型が、キャスト変換の規則(§5.5)に従ってキャスト演算子によって指定された型にキャストされない場合は、コンパイル時エラーになります。それ以外の場合、実行時に、オペランド値は、キャスト演算子によって指定されたタイプに変換をキャストすることによって(必要に応じて)変換されます。

セクション5.5では、キャスト変換について説明します。許可されている変換タイプのリストが表示されます。特にリストに含まれていないのは、「開開変換とそれに続く拡大/縮小プリミティブ変換」です。ただし、その正確な変換シーケンスは、javacコンパイラー(およびEclipseコンパイラー)によって許可されているようです。例えば:

long l = (long) Integer.valueOf(45);

...正常にコンパイルされます。(問題のあるキャストはへのキャストlongです。引数はタイプであるため、変換にはボックス化を解除してから、プリミティブ変換を拡張java.lang.Integerする必要があります)。int

byte同様に、JLSによると、からへのキャストは不可能です。これは、( 5.1.4charによると)プリミティブ変換の拡大とプリミティブ変換の縮小が必要なためです。ただし、このキャストはコンパイラーによっても許可されます。

誰かが私を啓発できますか?

編集:これを求めて以来、私はOracleにバグレポートを提出しました。彼らの反応は、これが「JLSのグリッチ」であるというものです。

4

2 に答える 2

3

私はあなたが正しいと思います、コンパイラは正しいです、そしてスペックは間違っています...。

これはコンパイルします:(Object)45そしてこれはしません:(Long)45

コンパイラーの動作(私が使用しているIntellijを含む)を理解する唯一の方法は、キャスト変換が割り当て変換とメソッド呼び出し変換に同意するように変更されている場合です。

  • ボクシングの変換(§5.1.7)とそれに続く拡張参照変換

  • 開開変換(§5.1.8)の後に、オプションで拡張プリミティブ変換が続きます。

プラス

  • 原始的な会話の拡大と縮小

仕様では、「キャスト変換は、代入またはメソッド呼び出し変換よりも包括的です。キャストは、文字列変換またはキャプチャ変換以外の許可された変換を実行できます」と述べています。

于 2011-03-22T02:45:00.700 に答える
1

私の読書によると、からintへのキャストlongはこの節で許可されています:

プリミティブ型の値は、型が同じである場合はID変換によって、またはプリミティブ変換の拡大またはプリミティブ変換の縮小によって、別のプリミティブ型にキャストできます。

に変換intすることlongは、拡張プリミティブ変換です。

Integerこれで、からへの変換intが残ります。これは、最後の箇条書きで対応されています。

開箱変換

もちろん、このlong例では、キャスト先は必要ありません。

次の4つの定義を検討してください。

final Integer io = Integer.valueOf(45);
final int i = io;
final long l1 = (long)i;
final long l2 = i;

それらのどれかが驚くべきものだと思いますか?元の例は何も変わりません。中間変数を削除するだけです。

于 2011-03-22T02:28:43.713 に答える