型変換 (キャスト)

生田 陸人
LuaGate エンジニア / 現役エンジニア
編集 LuaGate編集部

型変換 とは

Java の自動型変換と明示的キャスト (double) (int) を理解して、整数除算と小数除算を自在に切り替えられるようになろう。

型変換 (キャスト) とは

Java は強い型付けの言語です。intdoublelongint のように、数値同士でも「型」が違うとそのままでは混ぜて使えません。たとえば int a = 3.14; と書いてもコンパイルエラーになります。なぜなら 3.14doubleaint で、サイズも表現できる範囲も違うからです。

そこで登場するのが 型変換 (キャスト) です。型変換とは、ある型の値を別の型の値に「変換する」操作のことを指します。日本語では「キャスト」「キャスティング」とも呼ばれ、Java を含む多くの静的型付け言語で頻繁に登場します。

型変換は、数学的な計算結果を変えるためのものではなく、「この値を、別の型として扱いたい」という意思表示です。intdouble として扱えば小数演算ができるようになり、doubleint に押し込めば小数部分を切り捨てた整数が得られます。

キャストには大きく分けて 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 〜 127
  • short — 2 バイト、−32768 〜 32767
  • int — 4 バイト、約 ±21 億
  • long — 8 バイト、巨大な整数
  • float — 4 バイト、単精度浮動小数点
  • double — 8 バイト、倍精度浮動小数点

byte → short → int → long → float → double の順に「右側ほど大きい」型です。左から右への変換は自動、右から左へは明示的キャストが必要、というルールになっています。

int から float への変換は自動ですが、float は仮数部が 23 ビットしかないため、巨大な intfloat に変換すると 精度が落ちる ことがあります。コンパイルは通っても、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 の整数除算が実行され、結果の 3double にしているだけなので、欲しかった 3.5 にはなりません。キャストは「割り算する 」のオペランドに掛けてください。

Java の型変換の流れ

今回の課題 divideDouble(int a, int b) で行われる型変換の流れを図にしてみましょう。inta をキャストして double にしてから割り算し、結果の double を呼び出し元に返すまでをイメージしてください。

diagram (will load when visible)

片方を double にキャストすると、もう片方も自動的に double格上げ (promotion) されてから演算されるのが Java の仕様です。だから (double) a / b だけで両方が double 扱いになり、結果も double になります。

よくある間違い

キャストでハマりやすいポイントは次の 3 つです。

  • キャストの位置を間違える(double)(a / b) のようにカッコ全体に掛けると、先に整数除算してから double 化することになり、小数部が消えます。(double) a / b のように 割り算する前のオペランド にキャストするのが正解です
  • 桁あふれ (overflow)long → intint → 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) で、ab で割った結果を double で返します。

  1. 右側のエディタを開く
  2. b == 0 のときは return 0.0; でガードする
  3. それ以外は return (double) a / b; のようにキャストを使って、intdouble に変換してから割る
  4. 「実行」ボタンを押して、テストが緑になることを確認する

return a / b; と書くと整数除算になり、divideDouble(7, 2) の結果が 3.5 ではなく 3.0 になってテストが fail します。return (double)(a / b); も同じ理由で罠です。割り算する前 のオペランド (a または b) にキャストする、というルールを守ってください。

ゼロ除算については四則演算のレッスンでも触れましたが、int/ は右辺が 0 だと ArithmeticException で実行時エラーになります。ただし double の割り算は例外を投げず、InfinityNaN を返します。今回はキャストする前に 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 つができることを確認しましょう。

  1. キャスト の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. キャスト とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン

要件

  1. クラス名は Solution、メソッド名は divideDouble、引数は int a, int b の 2 つ、戻り値の型は double にすること
  2. 整数除算ではなく小数演算にするため、(double) キャストを使うこと (例: (double) a / b)
  3. 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

ヒント

main.java
main.java
学習モード

メモ

型変換 (キャスト)

⌘S で保存