👋

Javaの型変換についてざっくりまとめてみた[Java初心者]

に公開

Javaの型変換についてざっくりまとめてみた[Java初心者]

はじめに

こんにちは。
プログラミング初心者Wakinozaと申します。
Java勉強中に調べたことを記事にまとめています。

十分気をつけて執筆していますが、なにぶん初心者が書いた記事なので、理解が浅い点などあるかと思います。
記事を参考にされる方は、初心者の記事であることを念頭において、お読みいただけると幸いです。
間違い等あれば、指摘いただけると助かります。

対象読者

  • Java勉強中の方。
  • Java SE Bronze試験を勉強中の方。
  • Javaの拡大変換・縮小変換とその注意点についてざっくり知りたい方。

目次

1. 動的型付けと静的型付け
2. Javaの型変換
3. 変数代入時の型変換
4. 算術演算時の型変換
5. String型を含む演算時の型変換
6. 型の縮小変換

本文

1. 動的型付けと静的型付け

プログラミング言語は、データ型の決定方法によって、「静的型付け言語」と「動的型付け言語」の2つに分かれます。

静的型付け言語は、変数や式が型情報を持っています。式の型はコンパイル時にチェックされ、決定されます。変数に格納されたデータ型や式の結果のデータ型が、記述されたデータ型と違う場合は、コンパイルエラーになります。
動的型付け言語は、データ自身が型情報を持っています。変数代入時にもデータ型宣言が不要で、プログラム実行時にデータ型がチェックされます。

Javaは、静的型付け言語です。
コンパイラが型をチェックすることで、データ型違いによる実行時エラーを防いでいます。
静的型付けシステムによって、Javaはプログラムの堅牢性を向上させているのです。

Javaは原則として、あるデータ型で宣言された変数や式には、そのデータ型の値しか代入できません。
しかし数値型などでは、データ型を変換して利用できる機能があります。
これを「型変換」と言います。

2. Javaの型変換

型変換は、元の型と新しい型のどちらのデータサイズが大きいかによって、挙動が異なります。

参考までに、数値型のデータ型のサイズの大小関係は、以下の通りです。

byte < short < int < long < float < double

サイズが小さい型から大きい型への変換を「拡大変換」、サイズが大きい型から小さい型への変換を「縮小変換」と呼びます。

まず拡大変換の挙動を、「変数代入時の型変換」「算術演算時の型変換」「String型を含む演算時の型変換」の3点から見ていきます。

3. 変数代入時の型変換

変数代入時も原則として、宣言したデータ型と同じデータ型の値を代入しなければなりません。
しかし、数値型の拡大変換の場合、値のデータ型は、代入時に自動的に新しいデータ型に変換されます。コンパイラエラーも起きません。

以下のコードをご覧ください。

int a = 100;   //①int型にint型を代入
long b = a;    //②int型をlong型に代入
float c = a;   //③long型をfloat型に代入
double d = a;  //④float型をdouble型に代入
System.out.println(a);    //①結果:100
System.out.println(b);    //②結果:100
System.out.println(c);    //③結果:100.0
System.out.println(d);    //④結果:100.0

int型の変数aを、long型・float型・double型に代入してみました。
コンパイラエラーは起きず、新しいデータ型に変換されています。

数値型の拡大変換では、代入時に自動的に型が変換され、コンパイラエラーも起こらないことが確認できました。

4. 算術演算時の型変換

次に、算術演算時の型変換についてみていきます。

計算が行われる場合、算術演算子(+,-,*,/などのこと)を挟む左右のオペランドは、同じデータ型であることが原則です。

しかし、実際は異なるデータ型同士の計算も行えます。
オペランドのデータ型が違う場合、小さい方のデータ型を大きい方のデータ型に型変換する仕組みがあるからです。
Javaでは、違うデータ型同士の計算でも、データ型を揃えてから演算する仕組みになっているのです。

以下のコードをご覧ください。

double e = 7.5 / 2; //⑤double型とint型の演算
long f = 5 + 2L;    //⑥int型とlong型の演算
System.out.println(e);  //⑤結果:3.75 int型2をdouble型2.0に変換して演算
System.out.println(f);  //⑥結果:7 int型5をlong型5Lに変換して演算

double型とint型の演算と、int型とlong型の演算を行いましたが、コンパイルエラーなく実行できました。

算術演算時に注意が必要なのは、byte型とshort型です。
この2つのデータ型は、算術演算時に強制的にint型に変換される仕様となっています。そのため、byte同士、short同士の演算であっても、結果変数のデータ型はint型にしなければなりません。

byte b1 = 20;
byte b2 = 30;
byte b3 = b1 + b2;  //⑦注意 コンパイルエラーとなります
int i = b1 + b2;    //⑧ ⑦の演算を行うときは、結果のデータ型をintにする

5. String型を含む演算時の型変換

次に、文字列を含む演算時の挙動を確認します。

String型で+演算子を利用すると、文字列同士を結合することができます。では、String型と数値型を+演算子で結合するとどうなるのでしょうか。実は、+演算子で片方がString型の場合、もう片方も自動的にString型に変換されます。
以下のコードをご覧ください。

String s1 = "私の年齢は" + 20;  //①String型とint型の演算
String s2 = "私の身長は" + 165.5;  //②String型とdouble型の演算
System.out.println(s1);  //①結果:私の年齢は20
System.out.println(s1);  //②結果:私の身長は165.5

String型と、int型およびdouble型の演算を実施しました。
int型およびdouble型は、String型に自動的に変換され、コンパイルエラーなく実行できました。

6. 型の縮小変換

今まで、データサイズの小さい型から大きい型への拡大変換を見てきました。
では、大きい型から小さい方への縮小変換はどういった挙動になるのでしょう。

原則として、大きい型の値を小さい型に代入すると、コンパイラエラーになります。それは、保持できる桁が少なくなることで、データが失われる可能性があるためです。
どうしても縮小変換の必要がある場合は、キャスト演算子を使用します。
型変換させたい値の前にキャスト演算子「(変換させたい型)」を記述することで、強制的に縮小変換させることができます。

long g = 100L;  //③long型の100を代入
int h = g;      //④注意 long型をint型に代入するとコンパイラエラーになります
int i = (int)g; //⑤キャスト演算子でlong型をint型に変換
System.out.println(g);  //③結果:100
System.out.println(i);  //⑤結果:100

④でlong型をint型に代入するとコンパイラエラーになりますが、⑤でキャスト演算子を利用するとエラーなく代入することができました。

エラーは出ませんが、桁数の縮小によってデータの一部は失われている点に注意が必要です。場合によっては「桁あふれ」を起こし、データが破損してしまう場合もあります。

「桁あふれ」とは、桁数の縮小によってデータが破損してしまう現象です。
以下のコードご覧ください。

int j = 400;
byte k = (byte)j; //int型をキャスト演算子でbyte型に代入
System.out.println(k);  //結果:-112

int型の値をキャスト演算子で強制的にbyte型に代入しています。コンパイラエラーは起きませんが、結果が元の値と変わってしまっています。
何が起こっているのでしょう。

変数jに代入した値400を2進数で表すと9桁の「1 1001 0000」となります。byte型の容量は8桁のため、縮小変換すると一番左の桁がメモリに入り切らず、脱落してしまいます。8桁のbyte型に整えられた結果は、2進数で「1001 0000」10進数で-112を表しています。無理なキャスト変換によって「桁あふれ」が起き、データが破損してしまったのです。

キャスト演算子による縮小変換は、データの一部が失われることを承知の上で型変換を要求する命令です。コンパイラエラーは出ませんが、「桁あふれ」を起こし、データが破損させてしまうリスクもあります。予期せぬ不具合の原因にもなり得るので、取り扱いには十分注意が必要です。


記事は以上です。
最後までお読みいただき、ありがとうございました。

参考文献

この記事は以下の情報を参考にして執筆しました。

GitHubで編集を提案

Discussion