1. はじめに
Java には異なる2つのデータ系統があります。1つ目はプリミティブ型で、int、char、double、boolean などです。これはシンプルで高速で、値はメモリのセルに直接保存されます。2つ目は参照型、つまりオブジェクトで、変数はメモリ上のオブジェクトの場所への参照を保持します。
ときどきプリミティブをオブジェクトとして扱う必要があります。しかしプリミティブは本来オブジェクトではありません。そのような場合に役立つのが特別な ラッパークラス です。
ラッパー型とは、内部にプリミティブの値を保持し、それをオブジェクトとして扱えるようにするクラスです。たとえば、int には Integer、double には Double、char には Character、boolean には Boolean のクラスがあります。これらのクラスは Integer.parseInt()、Double.isInfinite()、Character.isLetter()、Boolean.parseBoolean() などのメソッドを提供します。
Integer オブジェクトを int プリミティブから得る例:
// プリミティブ
int a = 10;
// ラッパーオブジェクト
Integer b = Integer.valueOf(10);
変数 a には数値 10 自体が格納されます。一方、変数 b には、その内部に 10 を保持するオブジェクトへの参照が格納されます。
2. なぜラッパーが必要か
プリミティブは常に具体的な値であり、null にすることはできません。オブジェクトは存在しない(空の)値を持てるため、「不明」や「未設定」を表したいときに便利です。
プリミティブにはメソッドがありません。数値に対して x.toString() のような呼び出しはできません。ラッパーはそのような機能を提供します。たとえば Integer.parseInt("123") は文字列を数値に変換し、数値は toString() で文字列に変換できます。
まとめると、ラッパーはオブジェクトが必要な場面で使います。つまり null を保持できること、メソッドを呼び出せること、オブジェクトしか受け取らない API(たとえば List<Integer> のようなコレクション)に値を渡せること、などです。
ラッパー型の一覧
| プリミティブ型 | ラッパークラス |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3. ボクシングとアンボクシング
手動でラッパーオブジェクトを作成する場合、プリミティブをオブジェクトに「ボクシング」します:
int primitive = 42;
Integer wrapper = Integer.valueOf(primitive); // ボクシング
元のプリミティブ値を取り出すには、たとえば intValue() を使って「アンボクシング」します:
Integer wrapper = Integer.valueOf(42);
int primitive = wrapper.intValue(); // アンボクシング
オートボクシング (Autoboxing)
プリミティブをラッパー変数に代入すると、コンパイラが自動的に valueOf() 呼び出しを挿入します:
int a = 10;
Integer b = a; // オートボクシング (Integer.valueOf(a))
オートアンボクシング (Unboxing)
逆に、プリミティブが必要な場面でラッパーオブジェクトが使われると:
Integer c = 20;
int d = c; // オートアンボクシング (c.intValue())
int a = 10; // プリミティブ
Integer b = a; // オートボクシング
Integer c = Integer.valueOf(20);
int d = c; // オートアンボクシング
4. 落とし穴
ラッパーの比較。 演算子 == は、オブジェクトでは値ではなく参照を比較します:
Integer m = 200;
Integer n = 200;
System.out.println(m == n); // false(異なるオブジェクトだから)
Java は -128 から 127 の範囲の数値ラッパーをキャッシュするため、== が true になることもあれば false になることもあります。値の比較には常に equals() を使いましょう:
Integer x = 100;
Integer y = 100;
System.out.println(x == y); // true(キャッシュの範囲に入る)
System.out.println(x.equals(y)); // true(値の比較)
オートアンボクシング時の NullPointerException。 ラッパーが null のままアンボクシングしようとすると、例外が発生します:
Integer value = null;
int primitive = value; // エラー! NullPointerException
性能とメモリ。 ラッパーはプリミティブより遅く、メモリ使用量も多くなります。ホットパスや大きな数値配列を扱うときはプリミティブを選びましょう。
5. 例
Integer と Double の例
文字列を数値に変換:
String text = "123";
int number = Integer.parseInt(text);
System.out.println(number); // 123
浮動小数点の特別な値を確認:
double d = 1.0 / 0;
System.out.println(Double.isInfinite(d)); // true
double nan = 0.0 / 0.0;
System.out.println(Double.isNaN(nan)); // true
Character の例
char は 1 文字を保持し、ラッパーの Character には便利な判定メソッドがあります:
char ch = 'A';
Character wrapper = ch; // オートボクシング
System.out.println(Character.isLetter(ch)); // true
System.out.println(Character.isDigit(ch)); // false
System.out.println(Character.toLowerCase(ch)); // 'a'
Boolean の例
プリミティブの boolean は true/false のみですが、ラッパーの Boolean なら null も保持できます:
Boolean flag = null; // 許可される
flag = Boolean.TRUE; // 特別な定数
System.out.println(flag); // true
文字列を論理値に変換:
String s1 = "true";
String s2 = "false";
boolean b1 = Boolean.parseBoolean(s1);
boolean b2 = Boolean.parseBoolean(s2);
System.out.println(b1); // true
System.out.println(b2); // false
GO TO FULL VERSION