強制型変換について
2022-02-07 09:31:54
まずは例題から。
<スパン 実はこれはコンパイラの判断で、どちらも直接計算すれば結果が得られる定数なので、コンパイラは結果の値が左の型の範囲内かどうかを判断し、範囲内なら値を代入し、そうでなければ同様にエラーを報告するのです。
この情報はクラスファイルの中にあるので、JDK独自のjavapツールを使って見ます(javap -c Test)。
ちょっとした検証はここでできます。
(p.s. JDK1.6以上ではこの方法でテストしています)
ここで2つ目の難問が発生する。
続けてjavapツール(JDK 1.8)を使って見てみましょう。
char c=1;
c=c+3;
/*
error: incompatible types: possible lossy conversion from int to char
c=c+3;
^
*/
char c=1;
c=1+3;
<スパン <スパン コンパイル時にエラーが発生しました。
char c=1; //0: iconst_1 puts constant 1 on top of the stack
// //1: istore_1 stores the value 1 at the top of the stack into local variable 1, i.e. c
c=1+3; ///2: iconst_4 puts constant 4 on the top of the stack
// // 3: istore_1 stores the value 4 at the top of the stack into the local variable 1, i.e. c
<スパン 二項演算子 "+"記号のオペランドは、合計される型が同じでなければならず、その後、左変数に代入され、最終的な型は左変数によって決められます。型が一致しない場合、Javaは次の方向に、デフォルト変換(または自動型昇格)を試行します。
<スパン
(a) Javaでは、型の範囲が小から大になると自動変換を行い、逆に大から小になると精度が落ちる可能性があるため、強い変換(キャスト)を必要とします。
この例では、変数 "c" が char 型、定数 "3" が int 型として扱われ、加算時には char が自動的に int に変換され、これは正常ですが、代入時には int を char に変換する必要があり、精度が落ちてエラーが報告されています。
強力な変換を行うには、変換先の型を括弧で囲み、その後に変換する変数名を指定する必要があります(例:c=(char)(c+3))。
ここで、以下のコードがエラーを報告しないことを不思議に思うのは簡単です。
char c=1;
c=65535+1;
<スパン <スパン 2行目では、定数"1"と"3"はどちらもint型であり、代入もcharに変換されませんが、ここでは強い変換がないのは正常です、なぜですか? <スパン
<スパン 実はこれはコンパイラの判断で、どちらも直接計算すれば結果が得られる定数なので、コンパイラは結果の値が左の型の範囲内かどうかを判断し、範囲内なら値を代入し、そうでなければ同様にエラーを報告するのです。
この情報はクラスファイルの中にあるので、JDK独自のjavapツールを使って見ます(javap -c Test)。
char c=1;
c+=65535;
<スパン <スパン (a) コンパイラが "1+3" に対して演算を行い、結果 "4" を直接得たが、これは char 型の範囲内なので、そのまま代入できる、c=c+3 に変更すると、型によって決まる特定の値を取得できず、エラーとなる。
ちょっとした検証はここでできます。
char c=1;
c+=65535;
c=(char)(c+65535);
/* 0: iconst_1
1: istore_1
// The following is c+=65535;
2: iload_1
3: ldc #2 // int 65535
5: iadd
6: i2c // strong conversion: int to char
7: istore_1
// the following: c=(char)(c+65535);
8: iload_1
9: ldc #2 // int 65535
11: iadd
12: i2c // strong turn
13: istore_1
*/
<スパン
<スパン
をコンパイルすると、charは2バイト長なので、範囲は0〜2^16-1すなわち0〜65535で、定数和ではありますが、結果がcharの範囲を超えてしまうとint型として扱われ、その後に代入がまだ強回転する必要があるため、同じエラーとなりました。
(p.s. JDK1.6以上ではこの方法でテストしています)
ここで2つ目の難問が発生する。
char c=1;
c+=65535;
<スパン
上記のコードが正しくコンパイルされ、実行されるのはなぜですか?
続けてjavapツール(JDK 1.8)を使って見てみましょう。
char c=1;
c+=65535;
c=(char)(c+65535);
/* 0: iconst_1
1: istore_1
// The following is c+=65535;
2: iload_1
3: ldc #2 // int 65535
5: iadd
6: i2c // strong conversion: int to char
7: istore_1
// the following: c=(char)(c+65535);
8: iload_1
9: ldc #2 // int 65535
11: iadd
12: i2c // strong turn
13: istore_1
*/
複合代入演算子ステートメント: "c+=65535;" は "c=(char)(c+65535);" と同等なので、コンパイルしてエラーなく実行できることがわかりますが、特に値を2進コードに変換することで望む結果とは異なることがあります。
最後に、char, byte, shortは見かけ上の型であり、下部でintに変換されるため、"c=c+c;"という記述も強変換してコンパイルを通さなければならないのです。
関連
-
アクセス制限です。タイプ 'JPEGCodec' は API ではない ☞My Blog Github ☜ ホームページを見る
-
Collections.sortがdoubleでソートできない問題を完璧に解決する。
-
Javaクラスが "Error occurred during initialization of boot layer "というエラーで実行される。
-
スレッド "main" での例外 java.lang.ArrayIndexOutOfBoundsException:5 エラー
-
無効な文字定数
-
Javaジェネリックを1つの記事で
-
-bash: java: コマンドが見つからない 解決方法
-
代入の左辺は変数でなければならない 解答
-
htmlとwordの相互変換の実装(画像あり)
-
swagger2 モデルが表示されない モデルが見つからない @ApiModel アノテーションが表示されない問題
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
NullPointerException - java.lang.
-
ApplicationContextの起動エラーです。条件レポートを表示するには、アプリケーションを'de'で再実行します。
-
Uncaught ReferenceError: は定義されていません。
-
Java Notes 005_この行に複数のマーカーがある - キーを変数に解決できない - シンタックスエラー、ins
-
java.sql.SQLException: 結果セットの開始前
-
X11 DISPLAY変数が設定されていない」問題の解決方法
-
Javaがリソースリークに遭遇した:'input'が閉じない 解決方法
-
春ブート複数のデータソースの管理(atomikos)同じサーバーホスト上の複数のプロジェクトを開始する複数のJava - jarのエラーソリューション
-
テストが空であるかどうかを判断するためのオプションの処理
-
switch case文のcaseの後の列挙定数は列挙型なし