ボックス化ボックス化(boxing)[1]とは、プログラミング言語において値型をオブジェクト型(参照型)に変換すること。逆に、ボックス化されたオブジェクトを値型に戻すことをボックス化解除(unboxing)[2]と呼ぶ。 概要Javaや.NET Frameworkなどの環境においては、値型(Javaではプリミティブ型[3]がこれに相当する)と参照型という根本的に異なる二種類の型が存在する。参照型のインスタンスはヒープ上の独立した領域に確保される。値型は文脈によって確保される場所は異なるものの、いずれにせよメモリ上に連続的に確保される(例えば、ローカル変数として宣言された場合はスタック上に確保され、参照型のメンバとして宣言された場合は参照型の一部として確保される)。 このように値型と参照型とは根本的に性質の異なるものであるが、さまざまな理由により、値型を参照型に型変換して運用することが必要となる場合がある。Javaにおいて整数型や浮動小数点数型といったプリミティブ型はオブジェクト( 次はJavaによる例である。プリミティブ型のひとつである int iv1 = 100;
Integer iw = new Integer(iv1); // ボックス化。
int iv2 = iw.intValue(); // ボックス化解除。
一見単純な型変換のように見えるが、ボックス化においてはヒープ上に新しく領域を確保し、そこに値型(プリミティブ型)のデータをコピーするという操作が行われているため注意が必要である。頻繁なボックス化の発生は性能の低下を引き起こす。一方、ボックス化解除ではデータのコピーが行われるだけであり、ヒープに領域を確保する必要がないのでパフォーマンスコストは比較的小さい。 なお、ゼロ近傍の整数などのよく使われる数値に対して使いまわせるように事前生成されている、ラッパーオブジェクトのキャッシュを優先的に利用できるようにするため、通例 int iv1 = 100;
Integer iw = Integer.valueOf(iv1); // ボックス化。
関数型言語におけるボックス化関数型言語でも用いられることがあるが、オブジェクト指向のそれとの関連性はまったくない。ボックス型は単なる間接参照であり、Javaのプリミティブ型に相当する型は非ボックス型(Unboxed type)やプリミティブ型と呼ばれ、直接参照される。関数型言語のひとつであるHaskellでは、そのデファクトスタンダードな処理系であるGHCに対してコンパイラオプションを指定し、なおかつ非ボックス型であることを随所で明示しない限り、非ボックス型を用いることができない。にもかかわらず、知らず識らずのうちに利用している、馴染み深い型でもある。IO型など、副作用を表現する型がその典型例である。 自動ボックス化前述のボックス化・ボックス化解除の操作を暗黙的に行なうことを、自動ボックス化(autoboxing)[5]および自動ボックス化解除(auto-unboxing)と呼ぶ。 自動ボックス化はJava SE 5 (J2SE 5.0, Java 1.5) で追加され、JSR 201で宣言されている。自動ボックス化がサポートされた処理系では、対となる逆の操作、自動ボックス化解除もサポートされる。 以下のコードは自動ボックス化・自動ボックス化解除の例である。 int iv1 = 100;
Integer iw = iv1; // ボックス化。
int iv2 = iw; // ボックス化解除。
Javaコンパイラによって、プリミティブ型とプリミティブラッパークラス間の暗黙変換は、前述のようなボックス化・ボックス化解除を実行するコードに展開される。 .NET.NETにおいては、概念(型システム)上、値型も含めすべての型は C#の例を示す。 int iv1 = 100;
object iw = iv1; // 暗黙的なボックス化。
int iv2 = (int)iw; // ボックス化解除。
明示的なボックス化も可能ではあるが、通例使われない[6]。 object iw = (object)iv1; // 明示的なボックス化。
コレクションの例Javaでは、配列以外のコレクション( import java.util.*;
...
List list = new ArrayList(); // Object 型のみ格納できる。
//list.add(5); // Java 1.4 以前ではコンパイルエラー。
list.add(Integer.valueOf(5)); // Integer 型にボックス化してリストに追加する。
Integer iw = (Integer)list.get(0); // Object 型から Integer 型にダウンキャスト。
int iv = iw.intValue(); // Integer 型からボックス化解除。
Java 1.5以降ではジェネリクスおよび自動ボックス化をサポートするので、プリミティブ型のデータもあたかもオブジェクトのように扱うことができる。ただしコレクションには参照型のみ追加できること、またボックス化・ボックス化解除が実行されることには変わりない。Javaのジェネリクスは型安全であることが保証されているだけであり、ジェネリクスを使わない場合と比べてパフォーマンス上の優位性はない[7]。 List<Integer> list = new ArrayList<Integer>(); // Integer 型のみ格納できる。
list.add(5); // int 型の値から自動的に Integer 型のオブジェクトにボックス化される。
int iv = list.get(0); // Integer 型のオブジェクトから自動的に int 型の値にボックス化解除される。
.NET.NET 1.1まではジェネリクスをサポートしなかったため、配列以外のコレクションにはJava同様にボックス化・ボックス化解除を利用する必要があった。 using System.Collections;
...
IList list = new ArrayList(); // object 型のみ格納できる。
list.Add(5); // object 型にボックス化してリストに追加する。
object iw = list[0];
int iv = (int)iw; // object 型から int 型にダウンキャストしてボックス化解除。
一方、.NET 2.0 (C# 2.0) 以降のジェネリクスでは値型を直接扱うことができ、Javaと違ってボックス化・ボックス化解除は発生しない。 using System.Collections.Generic;
...
IList<int> list = new List<int>(); // int 型のみ格納できる。
list.Add(5);
int iv = list[0];
脚注
関連項目
外部リンク
Information related to ボックス化 |