4

K.Sierra と B.Bates は著書「SCJP Study Guide」に次のように書いています。

"以下は正当byte b = 27;ですが、コンパイラが自動的にリテラル値を 1 バイトに縮小するためです。つまり、コンパイラはキャストを挿入します。前のコードは次のコードと同じです:byte b = (byte) 27; "

私の意見では、この説明は正しくありません。この 2 行のコードは同一ですか?

実際には

byte b = 27;

は単なる定数です。そして、このコードが有効である唯一の理由は、コンパイル時の定数の縮小です。したがって、キャストは必要ありません。絞り込むとき、コンパイラは、指定された値が変数の型に適合するかどうかをチェックするだけです。仕様には次のように書かれています。

変数の型がbyteshort、またはcharであり、定数式の値が変数の型で表現できる場合、縮小プリミティブ変換を使用できます。

2番目のケースでは

byte b = (byte) 27;

キャストは実行時に発生し、プリミティブ値は特定のルールに従って計算されます。コンパイラは、プリミティブ型の互換性を気にしません。例えば

byte b = 5.0; // compile error
byte b = 277777777; // compile error
byte b = (byte) 5.0; // valid!
byte b = (byte) 277777777; // valid!!

こう考えると、拡大縮小変換とキャストは根本的に違うと思います。しかし、さまざまなソースで、それらはしばしば同じ意味で使用されます。これは正しいです?暗黙の縮小変換の場合、キャストはカバーの下で発生しますか?

上記の本で説明されている状況でのコンパイラの実際の動作を説明できる人はいますか?

4

2 に答える 2

2

始める前に、Java では純粋な数値リテラルはすべてint値であることに注意することが重要です。

許容されるキャストされていない定数に関する重要なフレーズは、変数の型で表現できることです。これは、定数が変数型の「範囲内」であることを意味するため、次のようになります。

  • byte -128~127用
  • short -32768 ~ 32767の場合
  • char 0 ~ 65535の場合

変数型にキャストされた場合、「範囲内」の値は「情報を失う」ことはありません。これは、範囲内の定数が許可される理由を説明しています。

範囲外の値の場合、キャストが実行されると情報が失われるため、明示的なキャストが必要です。縮小キャストが行われると、変数型の範囲外のビットは単純にマスクされます。これが、これらの場合の「情報の損失」を意味します。

定数の代入は次のようになります。

byte b = nnn & 0xFF;

nnn が範囲内にある場合、マスクは値を変更しないため、何も失われないため、問題なくコンパイルできます。

nnn が範囲外の場合、情報が失われるため、明示的なキャストで損失を確認する必要があります。

すべての整数リテラルが int であることを思い出すと、値が "適合" することがわかっている場合、コンパイラがキャストを許可しないことを除いて、規則は int をより狭い変数型に割り当てる場合に適用される規則と実際には違いはありません。

于 2013-06-25T14:49:52.713 に答える