型の変換
5.2 型の変換
Java では、値を変数に代入する時は必ず同じ型にしなければならないというルールがあります。もし違う型の値を代入する場合には、型変換を行う必要があります。
型変換は、自動で行われる場合と、明示的にしなければならない場合(キャスト)の二通りがあります。
5.2.1 自動で行われる型変換
まず、自動的に別の型に変換してくれる場合を見ていきましょう。自動で型変換が行なわれるのは、データの損失がない場合に限られます。
データの損失がない場合というのは、例えば、下記のようなケースです。
ここで使っている「10」は、int 型の値ですが、自動で型変換され、double 型の変数に代入することができるようになります。
double 型は小数を含む値を扱うためのデータ型(つまり、double 型は int 型より精度の高いデータ型)なので、int 型の値 10 は double 型に合わせて自動的に型変換が行われ、dounble 型の変数 d に代入された値は「10.0」になります。
図 5.2.1 : 自動で行われる型変換の例
逆に、int 型の変数に double 型の値を代入する場合はどうでしょうか。
次のように、double 型の値である「10.5」を int 型に代入しようとするとコンパイルエラーになってしまいます。それは、整数を扱う int 型の変数に、double 型の小数点以下の数値(0.5)を入れることができないからです。
図 5.2.2 : 自動で型変換が行われない例(この場合はコンパイルエラーになる)
このように、自動型変換が可能なのは、データの損失がない精度の低い型(小さい型)から精度の高い型(大きい型)に変換する場合に限られます。これは、大きな器にはそれより小さな物を入れられますが、小さな器には大きな物を入れることができないのと同じ考え方です。
ポイント・ 精度の低い型から精度の高い型へ自動型変換が行なわれます。(図の矢印の方向)
5.2.2 自動で型変換が行われることを確認するプログラム
基本データ型の変数を、同じく基本データ型の別の変数に代入する際に、自動的に型変換が行われる場合のプログラムを作成し、結果を確認します。
① ソース・フォルダー :myproj_intro/src
② パッケージ :jp.co.f1.intro.ch5
③ 名前 :ImplicitCast
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる
➢ ImplicitCast.java
package jp.co.f1.intro.ch5; public class ImplicitCast { public static void main(String[] args) { //int 型の平均点を管理する変数 int intAve; //double 型の平均点を管理する変数 double doubleAve; intAve = 65; System.out.print("平均点は"); System.out.print(intAve); System.out.println("点です。"); doubleAve = intAve; System.out.print("double 型に自動型変換すると"); System.out.print(doubleAve); System.out.println("点です。"); } }
実行結果
解説
8 行目で、int 型の変数 intAve を宣言しています。
図 5.2.3 : 変数の宣言
double 型の変数 doubleAve を宣言しています。
図 5.2.4 : 変数の宣言
13 行目で、8行目で作成した変数 intAve に値を代入しています。
図 5.2.5 : 値の代入
19 行目では、double 型の変数 doubleAve に int 型の値を代入しています。double 型は int 型よりも精度の高い型なので、データの損失が無く、自動型変換が行われます。65 という int 型(整数型)の値は、double 型(浮動小数点型)に変換され、65.0 となります。
図 5.2.7 : 別のデータ型に代入する際に自動的に型変換が行われる場合
5.2.3 明示的な型変換
自動型変換が行なわれるのは、精度の低い型から精度の高い型へ変換されデータが損失しない場合に限られるということを説明しましたが、データが損失することを認識したうえで、強制的(明示的)に型変換することもできます。これをキャストと呼びます。
キャストの基本構文は下記のとおりです。
5.2.4 明示的な型変換を行うプログラム
変数をキャスト(明示的に型変換)し、コンソールウィンドウに出力するプログラムを作成し、結果を確認します。
① ソース・フォルダー :myproj_intro/src
② パッケージ :jp.co.f1.intro.ch5
③ 名前 :ExplicitCast1
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる
➢ ExplicitCast1.java
package jp.co.f1.intro.ch5; public class ExplicitCast1 { public static void main(String[] args) { //double 型の平均点を管理する変数 double doubleAve; //int 型の平均点を管理する変数 int intAve; doubleAve = 65.5; System.out.print("平均点は"); System.out.print(doubleAve); System.out.println("点です。"); intAve = (int)doubleAve; System.out.print("int 型にキャストすると"); System.out.print(intAve); System.out.println("点です。"); } }
実行結果
解説
8 行目で、double 型の変数 doubleAve を宣言しています。
図 5.2.8 : 変数の宣言
11 行目で int 型の変数 intAve を宣言しています。
13 行目で、8 行目で宣言した変数 doubleAve に代入しています。
図 5.2.9 : 値の代入
19 行目では、int 型の変数 intAge に、double 型の変数 doubleAve を int 型にキャストして代入します。
小数点以下の数値を持つ double 型の 65.5 を、整数型である int 型に代入しようとするとき、小数点以下の 0.5を切り捨てなければなりません(自動的に四捨五入はしません)。このようなデータの損失があるときは、明示的な型変換(キャスト)が必要です。
図 5.2.10 : double 型の値を int 型にキャストして int 型の変数に代入
上の図の明示的な型変換の過程を説明します。まず double 型の 65.5 を int 型にキャスト(明示的に変換)します。その結果、小数点以下が切り捨てられ 65 になります。最終的にその値が int 型の変数 intAve に代入されます。
ポイント・ キャストが必要な方向下の図のようになります。
※ byte 型と char 型、short 型と char 型を互いに変換する場合は、常にキャストが必要です。
※ boolean 型と String 型は他の型と互換性がないので、キャストできません。
5.2.5 演算時の自動型変換
データ型の異なる値を組み合わせて計算した場合は、コンパイルエラーが起こるか、もしくは型が自動変換されます。
コンパイルエラーが起こる場合
その型の組み合わせの計算が不可能な場合は、コンパイルエラーが起こります。例えば下記のような場合です。
String 型や boolean 型はどの型と組み合わせても四則演算ができません。
データ型の自動変換が起こる場合
図 5.2.11 の矢印の方向が示すように、精度の高い型に合わせて変換されます。ただし、int 型より精度の低い型の場合、それらを組み合わせて計算すると int 型に変換されるので注意が必要です。
図 5.2.11 : 型の自動変換
5.2.6 違うデータ型同士の演算を行うプログラム
2 つの違うデータの型を使って演算を行い、結果を出力します。
① ソース・フォルダー :myproj_intro/src
② パッケージ :jp.co.f1.intro.ch5
③ 名前 :ImplicitCast2
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる
➢ ImplicitCast2.java
package jp.co.f1.intro.ch5; public class ImplicitCast2 { public static void main(String[] args) { //計算用の値を管理する変数を宣言し、値を代入 double d = 10.5; int i = 2; System.out.print("d = "); System.out.println(d); System.out.print("i = "); System.out.println(i); System.out.print("d + i : "); System.out.println(d + i); double doubleAnswer = d / i; // double 型に自動変換 System.out.print("d / i : "); System.out.println(doubleAnswer); double wrongDoubleAnswer = 3 / 2; System.out.print("3 / 2 : "); System.out.println(wrongDoubleAnswer); } }
実行結果
解説
8~9 行目は、double 型の変数 d を 10.5 で初期化し、int 型の変数 i は 2 で初期化しています。
17~18 行目の部分と実行結果を照らし合わせて下さい。double 型の値と int 型の値を加算すると、答えは「12.5」になります。
17 行目の「double 型 + int 型」の、型の異なる加算演算の過程を説明します。10.5 + 2 の計算では、まず int型の 2 が精度の高いほうである double 型に合わせて 2.0 に自動型変換が行われ、最終的に 10.5 + 2.0 の加算を行い、その結果は 12.5 になります。
20~21 行目は、double 型と int 型で除算を行います。答えの型を知るために、まず double 型の変数を作成し、そこへ答えを代入しています。エラーが無く正常に実行されたので、double 型と int 型の計算の答えは double 型であるということが分かりました。
20 行目の「double 型 / int 型」の、型の異なる割り算の過程を説明します。10.5 / 2 の計算では、まず int 型の2 が double 型に合わせて 2.0 に自動型変換が行われ、最終的に 10.5 / 2.0 の割り算を行うと、その結果は double型の 5.25 になります。その後得られた値 5.25 を double 型に代入します。
では、int 型と int 型の計算結果を double 型の変数に代入すると、どうなるのでしょうか。通常は 3 を 2 で割ると答えは 1.5 になりますが、24 行目で実行し、26 行目で結果を表示してみると 1.0 という結果になりました。
なぜ 1.0 という計算結果が出たかその過程を説明します。
ここでは「int 型と int 型との割り算」と「別のデータ型への代入」という2ステップに分けて考えましょう。
まず、先ほど説明したように 3 / 2 の割り算は通常 1.5 になりますが、Java では int 型同士の演算は int 型になるので、小数点が切り捨てられて、int 型の値1になります。その後に、int 型の値を double 型に代入します。int型の値1は double 型に代入されるときに、double 型に合わせて自動型変換が行われるので、その結果は 1.0 になります。
このように、違うデータ型同士の演算では、精度の低い型が精度の高い方に合わせて自動変換されて計算されますので、型の精度の順序を常にイメージしておくようにしましょう。
ポイント・ 違うデータ型同士の演算で、精度の低い型(小さい型)が精度の高い型(大きい方)に合わせて自動変換されて計算される。
5.2.7 違うデータ型同士の演算をキャストを使って行うプログラム
続いて、キャスト(明示的型変換)を使って、違うデータ型同士の演算を行います。
① ソース・フォルダー :myproj_intro/src
② パッケージ :jp.co.f1.intro.ch5
③ 名前 :ExplicitCast2
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる
➢ ExplicitCast2.java
package jp.co.f1.intro.ch5; public class ExplicitCast2 { public static void main(String[] args) { //計算用の値を管理する変数を宣言し、値を代入 double d = 3.4; int i = 2; System.out.print("d = "); System.out.println(d); System.out.print("i = "); System.out.println(i); double doubleAnswer = d * i; // 計算結果は自動型変換 System.out.print("d * i : "); System.out.println(doubleAnswer); int intAnswer = (int) (d * i); // 計算結果をキャスト System.out.print("(int)(d * i) : "); System.out.println(intAnswer); double wrongDoubleAnswer = (double)3 / 2; System.out.print("(double)3 / 2 : "); System.out.println(wrongDoubleAnswer); } }
実行結果
解説
17 行目の double 型と int 型の計算結果は、精度の高い方の型である double 型になります。
21 行目は同じ計算ですが、int 型の変数に答えを代入しています。
double 型と int 型の演算結果は、精度の高い方である double 型になるので、「d * i」の結果は「6.8」になります。しかし、double 型の値は、より精度の低い int 型にそのまま代入することはできません。これは、キャストすることによって、int 型の変数 intAnswer に代入することができます。
もし、これを int 型にキャストしなかったらどうなるのでしょうか。21 行目を下記のように書き換えて、保存をしてみましょう。
そうすると、下の図のようにコンパイルエラーが起こるはずです。赤い波線にマウスポインタを合わせ、エラーメッセージを確認してみて下さい。
25 行目から 27 行目は前項で使用したサンプルプログラム ImplicitCast2.java の最後で行った計算と同じように int 型と int 型の除算を行い計算結果を double 型の変数に代入しています。ただし、ImplicitCast2.java で行った計算と異なる点があります。
それは、除算を行う前に int 型の値に対して double 型へのキャストを行っている点です。
このように、予め小数点を扱える型にキャストを行うことで、小数点が切り捨てられてしまうことを防ぐことが可能です。
ポイント・ 精度の高い型(大きい型)を精度の低い型(小さい型)に代入する場合、明示的にキャストしなければならない。
※但し、int 型以下のみの型を利用した計算結果、全て int 型となる。
例) 「byte 型の値 + byte 型の値」の計算結果 int 型です。