Javaの型変換とキャストの基本
まず、「型」は値の種類を表すルールです。Javaは型に厳格なので、型が合わないと代入や計算でエラーになります。ここでは「自動で変わる場合」と「自分で変える必要がある場合」を、例題つきで丁寧に解説します。
自動型変換(拡大変換)
小さい器から大きい器へは、Javaが自動で安全に入れ替えてくれます。数値では次の方向は基本的に安全です。
- 順序: byte → short → int → long → float → double
- ポイント: 情報が増えたり減ったりしない方向は自動でOK。ただし浮動小数点は「誤差」に注意。
例1:intからdoubleへ(自動でOK)
int i = 100;
double d = i; // int → double に自動変換
System.out.println(d); // 100.0
Java例2:longからfloatへ(自動だが誤差あり得る)
long big = 1234567890123456789L;
float f = big; // 自動変換。ただしfloatは約7桁の精度しかない
System.out.println(f); // 桁が丸められて正確ではない値になる
Java- 注意: 浮動小数点の精度
- float: おおよそ7桁
- double: おおよそ15〜16桁
精度を保ちたいなら、金額やIDの計算には浮動小数点を避けることが多いです。
明示的な型変換(キャスト)
大きい器から小さい器へ入れるときは、あなたが「こうして!」と指示する必要があります。これがキャストです。
- 書き方:
(対象型) 値 - リスク: 端折られたり溢れたりします(切り捨てやオーバーフロー)。
例3:doubleからintへ(小数点を切り捨て)
double d = 123.45;
int i = (int) d; // 小数点以下が消える
System.out.println(i); // 123
Java- ポイント: 四捨五入ではありません。常に「切り捨て」です。
例4:longからintへ(範囲外だと壊れる)
long big = 3_000_000_000L; // intの最大値は約2.1億
int i = (int) big; // 範囲外。結果は別の値に化ける
System.out.println(i); // 予想外の値(オーバーフロー)
Java- 対策: 代入前に「入るか」チェックする。
long x = 123456789L;
if (x >= Integer.MIN_VALUE && x <= Integer.MAX_VALUE) {
int ok = (int) x;
} else {
// 入らないのでキャストしない、またはロジックを変える
}
Java数値リテラルの特例(直接書いた数は柔軟)
コードに直接書いた小さな数値は、範囲内なら小さい型にそのまま入れられます。
例5:byteとshortへの直接代入は範囲内ならOK
byte b1 = 10; // OK(-128〜127)
short s1 = 1000; // OK(-32768〜32767)
byte b2 = 128; // エラー(byteの範囲外)
Java- 注意: 変数を経由すると自動では縮まらない。
int i = 10;
byte b = i; // エラー:int → byte は縮小なのでキャスト要
byte b2 = (byte) i; // OKだが、入る値でもキャストが必要
Javaよくある落とし穴と対策
- 誤差の見落とし:
- ラベル: float/doubleの計算結果は端数がズレることがある
- 例: 0.1の足し引きが正確にならない
- 対策: 金額は整数(最小通貨単位)やBigDecimalを検討
- オーバーフロー:
- ラベル: 小さい型に入らない値をキャストすると別の値に化ける
- 対策: 事前に範囲チェック、または型を大きくする
- 意図しない切り捨て:
- ラベル: double→intで小数点が消える
- 対策: 必要なら丸め関数を使う(Math.round, Math.floor, Math.ceil)
double d = 12.7;
long r = Math.round(d); // 四捨五入(longが返る)
double f = Math.floor(d); // 切り捨て
double c = Math.ceil(d); // 切り上げ
Java練習問題
問題1:自動変換の確認
- 課題: 次のコードの出力を予想し、実行して確かめてください。
int i = 42;
double d = i;
System.out.println(d);
Java- 解説: 自動変換で42が42.0になります。精度は保たれます。
問題2:キャストの切り捨て
- 課題: 次の出力はどうなる?
double x = 9.99;
int y = (int) x;
System.out.println(y);
Java- 解説: 9になります。小数部分は常に切り捨てです。
問題3:オーバーフロー体験
- 課題: 実行して結果を確認し、なぜそうなるか説明してください。
long big = 2_147_483_648L; // intの最大値は2_147_483_647
int n = (int) big;
System.out.println(n);
Java- 解説: 範囲外キャストで負の値などに化けます。intが表せない範囲だからです。
問題4:リテラルと変数の違い
- 課題: 次のうちコンパイルできるのはどれ?
byte a = 100; // ①
int b = 100;
byte c = b; // ②
byte d = (byte) b; // ③
Java- 解説: ①と③はOK。②はint→byteの縮小なのでエラー。
問題5:安全なキャストの前チェック
- 課題: long値をintに安全にキャストするユーティリティを作る。
public static Integer toIntSafely(long v) {
if (v < Integer.MIN_VALUE || v > Integer.MAX_VALUE) {
return null; // 入らない
}
return (int) v;
}
Java- 解説: 範囲外はnullを返して呼び出し側で扱う。例外やOptionalにしても良い。
まとめと指針
- 自動変換: 小さい型 → 大きい型は安全。ただし浮動小数点の精度に注意。
- キャスト: 大きい型 → 小さい型は明示的に。切り捨て・オーバーフローのリスクを理解する。
- リテラル特例: 直接書いた数は範囲内なら小さい型に入るが、変数経由はキャストが必要。
- 実務のコツ: 金額・IDは整数や文字列、精密計算はBigDecimal、範囲チェックを徹底。
