Java | 型変換とキャスト演算子

Java Java
スポンサーリンク

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、範囲チェックを徹底。
Java
スポンサーリンク
シェアする
@lifehackerをフォローする
スポンサーリンク
タイトルとURLをコピーしました