概要:ここでは、greflectでジェネリック型を扱う場合に基本となる概念、 アンジェネリック(ungeneric)について解説します。 この手法によりジェネリックオブジェクトにその型引数の適用値を 封入することができます。 greflectでは封入された型引数の適用値を使用して、 ジェネリックオブジェクト間の代入可能性や実行可能性を検証します これにより型安全(type safety)なリフレクションを提供します。
greflectの動作は、あるオブジェクトの条件と密接に関連があります。 この概念は説明的な用語で呼ぶならば「型変数が解決可能」 「具象的に継承した」といったところでしょうか。 greflectでは簡単のため、アンジェネリック(ungeneric)と呼ぶ事にします。
さて、説明の都合上、アンジェネリックでないオブジェクトの例 から先に見てみましょう。
new Map<String,Integer>()
new GenericDao<Person>(connection)
参考文献:
Javaジェネリックを使ったコンパイル時の動的処理
Wikipedia: C SharpとJavaの比較
ジェネリック: Java vs C#
Java のジェネリックは単なる糖衣構文である
次はアンジェネリックであるオブジェクトの例を紹介します。 アンジェネリックでないオブジェクトのnew文をアンジェネリック オブジェクトを生成するよう修正するのは簡単です。次に アンジェネリックオブジェクトの例を見てみましょう。
new Integer(23)
new Map<String,Integer>(){}
new GenericDao<Person>(connection){} ここで作成される匿名クラスを仮にそれぞれ Anon1, Anon2とすると、 上のnew文は
new Anon1()
new Anon2(connection)
Anon1 extends Map<String,Integer>
Anon2 exterds GenericDao<Person> ここまでアンジェネリックのテクニックを使用して型変数に適用される 型をオブジェクトに封入する方法について説明してきました。 しかしアンジェネリックオブジェクトを作成したからといって Java VMがそれを解釈して適切に動作してくれるわけではありません。
Java標準リフレクションAPIはジェネリック型情報を参照しないため、 アンジェネリックオブジェクト決定した型以外のオブジェクトを 代入することを躊躇しません。つまり例えば、 a = new ArrayList(Integer) に a.add("String") をinvokeしてしまうことは簡単にできてしまいます。 当然その後のコードでおかしなことが発生する要因となるしょう。
でももし、ジェネリック型情報を取得し妥当性を検証しつつ リフレクションを実行するなら、こういった問題を回避して より安全にリフレクションを使用できると思いませんか? それがgreflectで行っていることです。