結論: 値の範囲が狭い型から広い型への代入は、キャストを書かなくてもコンパイラが自動で変換します(拡大プリミティブ変換)。順番は byte → short → int → long → float → double で、char は int 以上へ自動で変換されます。ただし int → float、long → float、long → double は「拡大」でも精度(下位の桁)が落ちることがあります。
自動で変換される組み合わせ
| 変換元 | 自動で代入できる変換先 |
|---|---|
byte |
short int long float double |
short |
int long float double |
char |
int long float double |
int |
long float double |
long |
float double |
float |
double |
注意点:
charとbyte・shortの間は、どちら向きも自動変換されません(charは符号なし 0〜65535、shortは符号あり −32768〜32767 で、互いに範囲を包含しないため)。booleanは他のどの数値型とも変換できません。
コード例
int i = 100;
long l = i; // OK: int → long
double d = l; // OK: long → double
char c = 'A';
int code = c; // OK: char → int(65)
int big = 16_777_217; // 2の24乗 + 1
float f = big; // OK だが精度が落ちる
System.out.println((int) f); // 16777216
byte a = 1, b = 2;
// byte sum = a + b; // コンパイルエラー: a + b の型は int
int sum = a + b; // OK
最後の例のとおり、byte・short・char 同士の算術演算は、計算の前に int へ拡大されます(数値昇格)。そのため結果は int になり、byte へ戻すにはキャストが必要です。
原理(なぜそうなるか)
拡大変換は、変換先の型が変換元の値の範囲をすべて表せる組み合わせです。値の大きさ(桁数のオーダー)が失われないため、言語仕様(JLS 5.1.2)はキャストなしの代入を認めています。
一方、float の仮数部は 24 ビット、double の仮数部は 53 ビットしかありません。int(32 ビット)を float に、long(64 ビット)を float や double に入れると、表せる範囲には収まっても下位の桁が丸められることがあります。上の 16_777_217 が 16777216 になる例がそれです。範囲は失われないが精度は失われうる、というのがこの3つの組み合わせの性質です。
(この初版はAIが作成。随時書き換え)