Java 逆引き集 | 型変換(キャスト、ボクシング/アンボクシング) — データ受け渡し時

Java Java
スポンサーリンク

型変換の概要(キャスト/ボクシング/アンボクシング)

異なる型どうしでデータを受け渡すとき、Javaは「キャスト(型変換)」で数値型を変えたり、「ボクシング/アンボクシング」でプリミティブ型とラッパー型を自動変換します。暗黙的キャストは安全な拡大変換で自動、明示的キャストは縮小変換で開発者が指示します。
ボクシングはプリミティブからラッパーへ、アンボクシングはラッパーからプリミティブへ自動変換する仕組みで、コレクションなど参照型しか扱えない場面で活躍します。


数値の型変換(暗黙/明示キャスト)

暗黙的キャスト(拡大変換)

  • 特徴: 小さい器から大きい器へ安全に拡張。コードにキャスト記号は不要。
  • 代表的な流れ: byte → short → int → long → float → double。
int x = 100;
long y = x;        // OK: int → long(自動)
float f = 5.0f;
double d = f;      // OK: float → double(自動)
Java

小さい型から大きい型への変換はJavaが自動で行います。

明示的キャスト(縮小変換)

  • 特徴: 大きい器から小さい器へ。データ損失の可能性があるため「(型)」で明示が必要。
  • 目的: 範囲が収まることを自分で保証する使い方が基本。
long m = 100L;
// short n = m;     // コンパイルエラー
short n = (short) m; // OK: long → short(明示キャスト)
double pi = 3.14;
int ip = (int) pi;   // 3(小数切り捨て)
Java

縮小変換は明示キャストが必須で、範囲外や小数切り捨てに注意します。

よくある落とし穴

  • オーバーフロー: 例えば、intの範囲外をshortへキャストすると値が巻き戻る。
  • 小数切り捨て: double→intは小数部が消える。
  • 算術昇格: 式中で小さい型が自動的にintに昇格し、結果型が変わることがある(例: byte + byte → int)。
  • char→int: 文字コード(Unicode値)に変換される。

参照型のキャスト(継承階層)

継承関係にあるオブジェクトは、上位型(親)へは暗黙的に代入でき、下位型(子)へは明示キャストが必要です。実体がその子型でない場合はClassCastExceptionになります。事前にinstanceofで確認するのが安全です。

class Animal { }
class Dog extends Animal { void bark() {} }

Animal a = new Dog();  // 親型への代入(暗黙的)
Dog d = (Dog) a;       // 子型へのキャスト(OK: 実体はDog)
d.bark();

// 安全なパターン
if (a instanceof Dog dog) {   // Java 16+ パターンマッチ
    dog.bark();
} else {
    System.out.println("Dogではありません");
}
Java

参照型の下位キャストは、実体がその型であることを前提に明示が必要で、instanceof確認が推奨です。


ボクシング/アンボクシング(プリミティブ⇄ラッパー)

基本ルール

  • ラッパー型: Boolean, Character, Byte, Short, Integer, Long, Float, Double。各プリミティブに一対一で対応 Qiita
  • ボクシング: プリミティブ → ラッパーへ自動変換。
  • アンボクシング: ラッパー → プリミティブへ自動変換。
// ボクシング(自動)
int i = 10;
Integer I = i;            // int → Integer

// アンボクシング(自動)
Integer J = Integer.valueOf(20);
int j = J;                // Integer → int

// コレクションでの自動変換
import java.util.List;
import java.util.ArrayList;
List<Integer> list = new ArrayList<>();
list.add(123);            // int が Integer に自動ボクシング
int first = list.get(0);  // Integer が int に自動アンボクシング
Java

8種のプリミティブ型にはそれぞれ対応ラッパーがあり、自動で相互変換されます。

注意点(現場でよく起こる)

  • nullのアンボクシング: IntegerがnullのままintへアンボクシングするとNullPointerException。null許容ならラッパーのまま扱う、もしくはデフォルト値で回避。
  • パフォーマンス: 大量ループでの頻繁なボクシングはGC負荷増。必要に応じてプリミティブ配列や専用APIを選ぶ。
  • 比較の落とし穴: ラッパー同士の==は参照比較。数値比較はequalsまたはアンボクシングして比較。
Integer a = 128, b = 128;
System.out.println(a == b);       // false(参照が別)
System.out.println(a.equals(b));  // true(値が等しい)

Integer k = null;
// int kk = k; // NullPointerException
int kk = (k != null) ? k : 0;     // 安全にデフォルト値
Java

nullのアンボクシングは例外の原因になりやすく、比較はequalsやアンボクシングで値比較に統一します。


文字列と数値の変換(受け渡しの定番)

数値→文字列

  • valueOf: もっとも簡単で高速。
int n = 42;
String s = String.valueOf(n);  // "42"
Java

文字列→数値

  • parse系: 入力検証と例外処理をセットで。
String s = "123";
int n = Integer.parseInt(s);     // 123
double d = Double.parseDouble("3.14"); // 3.14

// 失敗時のハンドリング
try {
    int x = Integer.parseInt("12a");
} catch (NumberFormatException e) {
    System.out.println("数字ではありません");
}
Java

文字列と数値の相互変換はvalueOf/parse系メソッドが基本です。入力不正時はNumberFormatExceptionを捕捉します。


例題と練習(解説つき)

例題1: 暗黙/明示キャストの違い

  • ねらい: 拡大と縮小の挙動を体感する。
int i = 100;
long l = i;            // 暗黙: OK
double pi = 3.14;
int ip = (int) pi;     // 明示: 3(小数切り捨て)

System.out.println(l);  // 100
System.out.println(ip); // 3
Java
  • ポイント: 拡大は自動/縮小は明示。小数が消えることに注意。

例題2: 参照型キャストの安全確認

  • ねらい: instanceofで例外を防ぐ。
Object obj = Math.random() > 0.5 ? "hello" : 123;
if (obj instanceof String s) {
    System.out.println(s.toUpperCase());
} else {
    System.out.println("Stringではありません: " + obj);
}
Java
  • ポイント: instanceofで型を見てからキャスト。ClassCastExceptionを未然に防ぐ。

例題3: ボクシングの落とし穴(null問題)

  • ねらい: nullアンボクシングの例外を理解。
Integer count = null;
// int c = count;                // NullPointerException
int c = (count != null) ? count : 0;
System.out.println(c);           // 0
Java
  • ポイント: nullかもしれない値はラッパーで保持し、使う瞬間にデフォルトで安全化。

例題4: 文字列→数値の堅牢変換

  • ねらい: 受け入れバリデーション+例外処理。
String input = "007";
try {
    int code = Integer.parseInt(input);
    System.out.println(code); // 7
} catch (NumberFormatException e) {
    System.out.println("数字のみ許可");
}
Java
  • ポイント: parse時は例外対策必須。先頭ゼロや空文字の扱いも設計に合わせて決める.

小さなレシピ(テンプレ)

  • 安全な縮小キャスト:
long v = 500;
int safe = (v >= Integer.MIN_VALUE && v <= Integer.MAX_VALUE) ? (int) v : 0; // 収まらない場合はデフォルト
Java
  • 比較の統一(ラッパー・null許容):
static boolean eq(Integer a, Integer b) {
    return (a == b) || (a != null && a.equals(b));
}
Java
  • コレクション受け渡し(プリミティブ→ラッパー):
List<Integer> ids = new ArrayList<>();
for (int id : new int[]{1,2,3}) ids.add(id); // 自動ボクシング
Java

次の一歩

  • 練習案:
    • 算術昇格の確認: byte/short/charの加算結果型をprintlnで確かめる。
    • オーバーフロー観察: 32768をshortへキャストしたときの値変化を確認。
    • nullセーフAPI: OptionalやObjects.requireNonNullで受け渡し契約を明確化。
タイトルとURLをコピーしました