型変換と昇格

型変換と昇格

このレッスンでできるようになること。byte や short の計算がなぜコンパイルエラーになるのかを説明でき、明示キャストで値がどう化けるかを計算できるようになります。

まず予測してください

次のコードのうち、コンパイルエラーになる行はどれでしょうか。

byte a = 10; byte b = 20; byte c = a + b; byte d = 10 + 20; byte e = 200; short s = 1; s = s + 1; s += 1;

答えと理由

エラーになるのは byte c = a + b;byte e = 200;s = s + 1; の3行です。

数値昇格

Java は byte、short、char どうしの算術演算を、いったん int に昇格させてから 計算します。だから a + b の型は byte ではなく int です。int を byte の変数に入れるには明示キャストが要るので、byte c = a + b; は「int を byte に変換できません」というエラーになります。値が 30 で範囲に収まっているかどうかは関係ありません。変数を使った時点で型の話になるのがポイントです。

定数畳み込み

一方 byte d = 10 + 20; は通ります。右辺がリテラルだけで組まれていて、コンパイル時に 30 と確定できるからです。この 30 は byte の範囲に収まっているので、コンパイラが黙って変換してくれます。byte e = 200; が通らないのは、200 が byte の範囲である -128 から 127 を超えているからです。同じリテラル代入でも範囲次第で結果が分かれます。

final が付いた変数も定数として扱われます。 final byte a = 10; final byte b = 20; byte c = a + b; は通ります。final の有無で結果がひっくり返る、というのが最上級の引っ掛けです。

複合代入は暗黙キャストを含みます

s = s + 1; はエラーですが、s += 1; は通ります。複合代入演算子にはキャストが内蔵されているからです。s += 1; は実質的に s = (short)(s + 1); と同じ意味に展開されます。同じように byte b = 10; b += 300; もコンパイルは通ってしまいます。エラーにならず、値が化けるだけです。

キャストで桁があふれると何が起きるか

明示キャストは、入りきらない上位ビットを黙って切り捨てます。例外は出ません。

  • (byte) 200-56 です。200 は8ビットに収まらないので、下位8ビットだけが残り、先頭ビットが1なので負の数として読まれます。10進では 200 から 256 を引いた値になります
  • (byte) 130-126 です。130 から 256 を引いた値です
  • (int) 3.993 です。小数点以下は四捨五入ではなく切り捨てです
  • (int) -3.99-3 です。0 に近づく向きに切り捨てられるので、-4 ではありません

広がる向きは自動、狭まる向きは手動

情報が失われない向き、つまり byte から short、int、long、float、double へ向かう変換は自動です。逆向きは必ずキャストが要ります。例外的に注意したいのが char で、char は符号なしなので byte と char のあいだは両方向ともキャストが必要です。char c = 'A'; int n = c; は通りますが、char c2 = 65; byte b = c2; は通りません。

また long から float への変換は自動です。桁が落ちる可能性はありますが、Java は「表現できる範囲が広がる向き」を自動変換と決めているためです。ここも選択肢として狙われます。

まとめ

変数どうしの byte 演算は int になる、リテラルと final は定数として扱われる、複合代入はキャストを含む、キャストであふれた分は例外にならず黙って消えます。この4点が出題の核です。

要件

  1. byte 型の変数どうしの足し算の結果を byte 型の変数に収めること
  2. 200 と int 型の 130 を、それぞれ byte にキャストした値を求めること
  3. short 型の変数には複合代入演算子で 1 を足すこと
  4. 4つの値を半角スペース1つでつないだ文字列を返すこと

入出力例

convert()"30 -56 -126 2" convert()"30 -56 -126 2"

ヒント

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部
main.java
学習モード

メモ

型変換と昇格

⌘S で保存