型キャストとは
Javaは静的型付け言語です。すべての値には型があり、コンパイラは互換性のない型を暗黙のうちに混在させることを許しません。型キャストとは、値をある型から別の型へ変換する方法です。Javaが自動で行ってくれる場合もあれば、明示的に指示しなければならない場合もあります。
方向は2つあります。小さい型から大きい型へ移すこと(intからdoubleへ)は安全で、自動的に行われます。大きい型から小さい型へ移すこと(doubleからintへ)はデータを失う可能性があるため、Javaはキャストで明示的に書くことを強制します。
拡大変換:自動的な変換
拡大変換は、値をより余裕のある型へ移します。何も失われないため、Javaはキャストなしで自動的に行います:
intの7はdoubleに収まり、7.0になります。数値の拡大の順序はbyte -> short -> int -> long -> float -> doubleであり、この連鎖に沿って左から右へ代入する場合はキャストが不要です。算術演算で型を混在させても多くの場合「そのまま動く」のはこのためで、Javaは小さい方のオペランドを先に拡大します。
縮小変換:明示的なキャスト
逆方向、つまり縮小変換ではデータが失われる可能性があるため、値の前に対象の型を括弧で付けない限り、コンパイラは拒否します:
(int) piがキャストです。何をするかに注目してください。ゼロ方向に切り捨て、単に小数部を捨てます。3.9は3になり、-3.9は-3になります。四捨五入はしません。四捨五入したい場合は、別のツールを使います:
キャストが切り捨てることを忘れるのは、初心者が最もよくはまるバグの一つです。「四捨五入した」数値が常に1つ小さい場合、たいていこれが原因です。
整数除算の落とし穴
この落とし穴には誰もが一度ははまります。両方のオペランドがintの場合、/演算子は整数除算を行い、余りを捨てます。しかも、doubleへの代入が行われる前にそうなります:
a / bは7 / 2であり、すべてintの演算で計算されるため3になります。その後でdoubleに拡大しても3が3.0になるだけで、.5はすでに失われています。先に片方のオペランドをdoubleにキャストすると((double) a / b)、式全体が浮動小数点演算となり、求めていた3.5が得られます。キャストするのは片側だけで十分で、Javaはもう一方をそれに合わせて拡大します。
縮小がオーバーフローするとき
キャストは値が収まるかどうかをチェックしません。収まらない場合、ビットは単に切り捨てられ、意外な結果になります。エラーも警告もありません:
300はbyteに収まらないため、上位ビットが捨てられて44になります。これは「静かな」データ損失です。プログラムは問題なく動き、間違った答えを返します。値が小さい型に確実に収まると分かっている場合にのみ縮小してください。
数値と文字列の間の変換
Stringはオブジェクトであって数値ではないため、(int)でキャストすることはできません。これはコンパイルエラーになります。変換には専用のメソッドを使います:
テキストから数値へはInteger.parseInt / Double.parseDoubleを使います。文字列が有効な数値でない場合(たとえば"hello")、これらはNumberFormatExceptionをスローします。数値からテキストへはString.valueOf(n)を使うか、単に""と連結します。n + ""はintをStringに変換するからです。"5" + 1(文字列"51"になる)と5 + 1(6になる)の違いに注意してください。Stringが関わった瞬間、+は連結を意味します。
オブジェクトのキャスト
キャストはプリミティブだけでなく、オブジェクト参照にも適用されます。継承の連鎖に沿って、参照を関連する型にキャストできます。親型への拡大は自動的ですが、下位へ縮小し直すには明示的なキャストが必要で、オブジェクトが本当にその型である場合にのみ安全です:
Object o = "hello";
String s = (String) o; // OK:oは実際にStringを参照している
Integer bad = (Integer) o; // コンパイルは通るが、実行時にClassCastExceptionをスローする
2つ目のキャストはコンパイルは通りますが、オブジェクトがIntegerではなくStringであるため、実行時にClassCastExceptionで落ちます。これは継承とポリモーフィズムに進めば本格的に出会います。今のところは、(Type)という構文がオブジェクトに適用された同じ考え方であることを知っておけば十分です。
次:if-else
キャストは値を作り変えることを可能にします。次のステップは、それらの値に基づいてプログラムに経路を選ばせることです。if-else文は条件が真のときに一方のブロックを、偽のときにもう一方のブロックを実行します。これはコードが下すあらゆる判断の基礎です。それが次のページです。
よくある質問
Javaの型キャストとは何ですか?
型キャストとは、値をあるデータ型から別のデータ型に変換することです。Javaは小さな「拡大」変換(intからdoubleなど)を自動的に行いますが、データが失われる可能性のある「縮小」変換(doubleからintなど)には明示的なキャストが必要です:int n = (int) 3.9;。
Javaでdoubleをintに変換するにはどうすればよいですか?
対象の型を値の前に括弧で書きます:int n = (int) 3.9;。これはゼロ方向に切り捨て(小数部を捨てる)ので、4ではなく3になります。代わりに四捨五入したい場合は、4を返すMath.round(3.9)を使います。
JavaでStringをintに変換するにはどうすればよいですか?
Stringは数値ではないので、(int)でキャストすることはできません。intを得るにはInteger.parseInt("42")を、doubleにはDouble.parseDouble("3.14")を使います。テキストが有効な数値でない場合、これらはNumberFormatExceptionをスローします。