Java Genericsの裏側を知る

文:Peter V. Mikhalenko(special to TechRepublic)  翻訳校正:原井彰弘
2007-12-14 18:04:01
  • このエントリーをはてなブックマークに追加

Java 1.5の先進機能であるGenericsを用いると、型に関するチェックが行えるようになり、CollectionインタフェースやArrayListクラスが扱うオブジェクトを特定のオブジェクト型に限定することが可能になる。

また、Genericsを用いると、オブジェクトのソートの際に正しい種類のComparatorを用いているかどうかもチェックすることが可能になる。この型チェックは、ほぼすべてコンパイル時に行われる(C++にはテンプレートと呼ばれる類似の機能がある)。

Genericsの動作

Javaの場合、Collectionインタフェースを実装するクラス(たとえば、HashMapクラス、ArrayListクラス、TreeListクラス)すべてにおいて、コレクションに含まれる要素はジェネリックなObjectオブジェクトとして扱われる。ここで問題なのは、コレクション内にどのような種類のオブジェクトが保持されているのかは、自分で管理する必要があるということだ。たとえば、DogオブジェクトのコレクションにCatオブジェクトを追加したとしても、コンパイラは何も警告をしないのである。そこで、Java 1.5ではGenericsが導入された。

しかし、このGenericsは高いオーバーヘッドを伴う手法で実装されている。コレクションに要素を追加する際にも、コレクションから要素を取り出す際にも、暗黙的な型キャストが必要となるのだ。コンパイラは、コレクションに追加されるすべてのオブジェクトを(たとえば)Dog型に自動的にキャストし、それらが取り出されるときには再びDog型にキャストする作業を自動で行うのである。一方、コレクションの内部では、それらの要素は単にジェネリックなObject型として扱われる。理論上は、これらの時間が掛かるキャストは2回とも必要ないのだが、キャストを除去すると、それがセキュリティホールとなってJVMの脆弱性につながる危険性があるため、取り除くことはできない。

新しい構文とオートボクシング

JavaにおけるGenericsでは、クラスの型パラメータには正式にはオブジェクト型しか指定することができない。つまり、List<Integer>はコンパイル可能であるが、List<int>はコンパイルできないのである。しかしオートボクシング機能によって、プリミティブのint型をList<Integer>に追加することは可能となっている。オートボクシングとは、型を変換するコードを記述しなくてもプリミティブ型をオブジェクト型として扱える機能である。型変換に必要なコードは、コンパイラが自動的に補ってくれるのだ。それによって、J2SE 5.0以降では、たとえばint型を扱うLinkedListを作成することが可能になっている。本来、LinkedListはオブジェクト型のみを対象としており、プリミティブ型のリストは作成できない。しかし、オブジェクトを受け取るべき時にプリミティブ型が渡されると、そのプリミティブ型は直ちにオブジェクトに変換されるのである。

この動作はオートボクシングと呼ばれている。ボックス化は暗黙的かつ自動的に行われるので、手作業で行う必要がなくなるのである。また逆に、ボックス化されたプリミティブ型から、数学的な処理などのためにプリミティブ型を取り出すことは、非ボックス化と呼ばれる。以下に、Genericsとオートボクシング機能を用いたコードの例を挙げる。

int z = 5;
List<Integer> digits = new Vector<Integer>();
Integer $int = (z * 32); // Boxing
digits.add(++$int); // Unboxing
$int = digits.get(0); // Boxing
boolean is33 = $int == 33; // Unboxing

Genericsは型の正確さを保つためコンパイル時にチェックされる。このチェックが終了すると、ジェネリック型の情報は「型消去」(type erasure)と呼ばれる処理によって削除され、その後はスーパークラスのためだけに保持される。例を挙げると、List<Integer>は任意のオブジェクトを含むことが可能な非ジェネリック型のListに変換されるのである。チェックはコンパイル時に行われるため、コンパイラが未チェックの警告を発しない限り、最終的なコードは型として正しいことが保証されるのである。

このサイトでは、利用状況の把握や広告配信などのために、Cookieなどを使用してアクセスデータを取得・利用しています。 これ以降ページを遷移した場合、Cookieなどの設定や使用に同意したことになります。
Cookieなどの設定や使用の詳細、オプトアウトについては詳細をご覧ください。
[ 閉じる ]