型変換 (キャスト)
型変換 とは
Java の自動型変換と明示的キャスト
(double)(int)を理解して、整数除算と小数除算を自在に切り替えられるようになろう。
型変換 (キャスト) とは
Java は強い型付けの言語です。int と double、long と int のように、数値同士でも「型」が違うとそのままでは混ぜて使えません。たとえば int a = 3.14; と書いてもコンパイルエラーになります。なぜなら 3.14 は double、a は int で、サイズも表現できる範囲も違うからです。
そこで登場するのが 型変換 (キャスト) です。型変換とは、ある型の値を別の型の値に「変換する」操作のことを指します。日本語では「キャスト」「キャスティング」とも呼ばれ、Java を含む多くの静的型付け言語で頻繁に登場します。
型変換は、数学的な計算結果を変えるためのものではなく、「この値を、別の型として扱いたい」という意思表示です。
intをdoubleとして扱えば小数演算ができるようになり、doubleをintに押し込めば小数部分を切り捨てた整数が得られます。
キャストには大きく分けて 2 種類あります。自動型変換 (拡大変換) と 明示的キャスト (縮小変換) の 2 つです。それぞれ見ていきましょう。
自動型変換 (拡大変換)
小さい型から大きい型へは、Java が 自動的に 変換してくれます。これを「自動型変換」または「拡大変換 (widening conversion)」と呼びます。情報量が増える方向なので、データが失われる心配がなく、安全に変換できるからです。
Java
int i = 10;
double d = i; // int → double に自動変換、d は 10.0
long l = i; // int → long も自動、l は 10
float f = 100; // int リテラル → float も自動、f は 100.0f型のサイズ感を確認しておきましょう。基本型のサイズは次の通りです。
byte— 1 バイト、−128 〜 127short— 2 バイト、−32768 〜 32767int— 4 バイト、約 ±21 億long— 8 バイト、巨大な整数float— 4 バイト、単精度浮動小数点double— 8 バイト、倍精度浮動小数点
byte → short → int → long → float → double の順に「右側ほど大きい」型です。左から右への変換は自動、右から左へは明示的キャストが必要、というルールになっています。
intからfloatへの変換は自動ですが、floatは仮数部が 23 ビットしかないため、巨大なintをfloatに変換すると 精度が落ちる ことがあります。コンパイルは通っても、123456789のような大きな整数はfloatだと近似値になります。シビアな数値計算ではdoubleを使いましょう。
明示的キャスト (縮小変換)
反対に、大きい型から小さい型へは Java が自動で変換してくれません。情報が失われる可能性があるため、プログラマが「失われてもいいから変換する」と明示する必要があります。これが 明示的キャスト または 縮小変換 (narrowing conversion) です。
文法は (変換したい型) を値の前に書きます。
Java
double d = 3.7;
int i = (int) d; // 3 (小数部は切り捨て、四捨五入ではない)
long big = 100000000000L;
int n = (int) big; // int の範囲を超えると値が壊れる
double pi = 3.14159;
int piInt = (int) pi; // 3ここで注意したいのが (int) のキャストは 四捨五入ではなく切り捨て ということです。3.7 をキャストしても 4 にはならず、3 になります。負の数の場合は (int) -3.7 が -3 (0 に近い側へ切り捨て) になります。四捨五入したい場合は Math.round を使います。
整数除算と小数除算の違い (再掲)
四則演算のレッスンで学んだとおり、int 同士の割り算は小数部が切り捨てられます。これを回避する手段こそが、まさに型変換 (キャスト) です。
Java
int a = 7;
int b = 2;
int r1 = a / b; // 3 (整数除算)
double r2 = a / b; // 3.0 (右辺の結果が int の 3、それを double に拡大)
double r3 = (double) a / b; // 3.5 (a を double にキャスト、b は自動的に double)
double r4 = a / (double) b; // 3.5 (b を double にキャスト、a は自動的に double)
double r5 = (double)(a / b); // 3.0 (これは罠! 先に整数除算で 3、その後キャスト)
r5の(double)(a / b)は 間違いの典型例 です。カッコの中で先にint / intの整数除算が実行され、結果の3をdoubleにしているだけなので、欲しかった3.5にはなりません。キャストは「割り算する 前」のオペランドに掛けてください。
Java の型変換の流れ
今回の課題 divideDouble(int a, int b) で行われる型変換の流れを図にしてみましょう。int の a をキャストして double にしてから割り算し、結果の double を呼び出し元に返すまでをイメージしてください。
片方を double にキャストすると、もう片方も自動的に double に 格上げ (promotion) されてから演算されるのが Java の仕様です。だから (double) a / b だけで両方が double 扱いになり、結果も double になります。
よくある間違い
キャストでハマりやすいポイントは次の 3 つです。
- キャストの位置を間違える —
(double)(a / b)のようにカッコ全体に掛けると、先に整数除算してからdouble化することになり、小数部が消えます。(double) a / bのように 割り算する前のオペランド にキャストするのが正解です - 桁あふれ (overflow) —
long → intやint → byteのような縮小変換で、変換先の範囲を超えると値が壊れます。たとえばint n = (int) 3000000000L;はintの上限 (約 21 億) を超えるため、まったく違う負の数になります。(int)のキャストはコンパイラに「失われてもいいから変換する」と伝える宣言なので、警告は出ません。範囲を超えていないか自分でチェックする責任があります (double)を片側だけに付けるのを忘れる —int a = 7, b = 2;のとき、double r = a / b;と書いても結果は3.0で、3.5にはなりません。整数除算してからdoubleに拡大しているだけだからです。少なくともどちらか一方に(double)を明示しないと、小数演算にはなりません
もうひとつ、Java で (int) キャストは 常に切り捨て で、四捨五入ではないことも覚えておきましょう。四捨五入したい場合は Math.round(3.7) のように Math クラスのメソッドを使います。
キャストは「型システムを黙らせる呪文」のように使うと、後で必ず痛い目を見ます。「なぜここでキャストが必要なのか」「キャストでどの情報が失われるのか」をコードを書く前に頭の中で説明できるようにしておきましょう。
やってみよう
それでは課題に挑戦してみましょう。今回のメソッドは divideDouble(int a, int b) で、a を b で割った結果を double で返します。
- 右側のエディタを開く
b == 0のときはreturn 0.0;でガードする- それ以外は
return (double) a / b;のようにキャストを使って、intをdoubleに変換してから割る - 「実行」ボタンを押して、テストが緑になることを確認する
return a / b; と書くと整数除算になり、divideDouble(7, 2) の結果が 3.5 ではなく 3.0 になってテストが fail します。return (double)(a / b); も同じ理由で罠です。割り算する前 のオペランド (a または b) にキャストする、というルールを守ってください。
ゼロ除算については四則演算のレッスンでも触れましたが、int の / は右辺が 0 だと ArithmeticException で実行時エラーになります。ただし double の割り算は例外を投げず、Infinity や NaN を返します。今回はキャストする前に b == 0 を判定して 0.0 を返すので、整数除算のゼロ除算例外も Infinity 化も両方避けられる安全な書き方になっています。
キャストは Java を書いていると一日に何回も登場する基本機能です。「自動変換は安全な方向、明示的キャストは情報が失われるかもしれない方向」というイメージを持って、迷ったら型のサイズ図を頭の中で思い出してみてください。
よくある質問
Q. Java と他言語の文法はどう違いますか?
A. Java は静的型付けで、変数宣言時に型を明示します(int x = 0;)。中括弧でブロックを表し、文末にセミコロンが必要です。Python の動的型付けや JavaScript の柔軟さに慣れていると最初は窮屈ですが、コンパイル時にバグが発見できる安全性がメリットです。
Q. コードが動かないときに最初に見るべき場所は?
A. コンパイルエラーは行番号とエラー種別(cannot find symbol、incompatible types など)が表示されます。実行時例外はスタックトレースの最初の at ... が原因行です。IDE(IntelliJ / VS Code)の警告も丁寧に潰すと、半分のバグは未然に防げます。
Q. Java の習得後に学ぶべき技術は何ですか?
A. 基本構文を抑えたら java-intermediate(コレクション / ジェネリクス / Stream / 例外)に進み、Spring Boot や Web 開発に展開するのが王道です。クラウド時代は Kotlin / Scala への展開も視野に入りますが、まずは Java 標準を固めるのが効率的です。
次のレッスン
次は 第 2 章 まとめクイズ で、第 2 章 まとめクイズ を学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- キャスト の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. キャスト とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
- クラス名は
Solution、メソッド名はdivideDouble、引数はint a, int bの 2 つ、戻り値の型はdoubleにすること - 整数除算ではなく小数演算にするため、
(double)キャストを使うこと (例:(double) a / b) b == 0の場合は0.0を返し、ArithmeticExceptionを発生させないこと
入出力例
test-cases.txt
divideDouble(7, 2) → 3.5
divideDouble(10, 4) → 2.5
divideDouble(5, 0) → 0
divideDouble(8, 2) → 4