Javaのリフレクション機能

java-reflecion.png


↑これはクリスティーナ・アギレラの歌う曲「 Reflection」です。
ディズニーアニメ映画のムーランの主題歌です。
よくアメリカン・アイドルで歌われています。

Javaのリフレクション機能とは?

java.lanf.ClassクラスはJavaのデータ型を表します。
そして、java.lang.reflectパッケージのクラスとの組み合わせで、
Javaに対してイintrospection1(自己リフレクション)の機能を提供します。
Javaのクラスは、自身や他の任意のクラスを見て、スーパークラスを調べたり、
そのクラスで定義されているメソッドを調べたりできます。

例:クラス名を調べる

public static void main(String[] args) {
         Object o=new Miffy();
         Class c=o.getClass();
         if(!c.isPrimitive()){
             System.out.println(c.getName());     
         }
    }

わぉ、便利!って思うけど、あまり使ったことがない。

その他にもこんな機能があります

getSuperclass() 親クラスを取得
newInstance() (そのクラスに引数なしのコンストラクタがあれば)インスタンス作成する
forName("クラス名") 指定された文字列名を持つクラスまたはインタフェースに関連付けられた、Class オブジェクトを返します。
getMethod("関数名") その名前を持つ関数があるか調べる。(あれば呼び出すことができる!!)

そうMethodというオブジェクトもあるのだ
Method.invoke()を呼べば、その関数を呼ぶことができるのだ!わお。関数オブジェクトみたい。コールバック関数にもできる??

リフレクションよりインタフェースを選ぶべし?

Effective Javaの項目53には「リフレクションよりインタフェースを選ぶ」と書いてある。
リフレクションはあまりお勧めでない様子だ。理由はというと、

  • コンパイル時型検査の恩恵を失う
  • リフレクションによるアクセスを行うコードはぎこちなく、冗長である
  • パフォーマンスが悪くなる(遅い)

なので、プログラムを作るときに、デバッグのために使うのなら良い。
リリース版のプログラムでは使わないことだね。
ただし、あなたの作ってるプログラムが、コード解析ツールだったとしたら、話は別。
そもそもリフレクションを必要とするときはいつなのか?
コンパイル時には存在いないクラスを使用しなければならないときである。
そういうとき、リフレクションを使うのではなく、インタフェースを使うのがよいのだそうだ。
うーん、どうやって書けばいいの?
たとえば次のコードはインタフェースの代わりにリフレクションを使うと、いかにコードが長ったらしく、かつランタイムエラーが起こるかを物語っている。

//インタエースアクセスでのリフレクションによるインスタンス化
import java.util.Arrays;
import java.util.Set;
public class Miffy {
    public static void main(String[] args) {
    //fakeargs[0]にはSetインタフェースの派生クラスを指定する。
        String[] fakeargs={"java.util.HashSet","Khloe","Kim","Kourtney","Khloe"};
        Class<?> cl=null;
        try{
            cl=Class.forName(fakeargs[0]);//もしjava.util.TreeSetだったらソートして出力されるはず
        }catch(ClassNotFoundException e){
            System.err.println("そのクラス名は見つかりません");
            System.exit(1);
        }
        Set<String> s=null;
        try{
            s=(Set<String>)cl.newInstance();//インスタンス化
        }catch(IllegalAccessException e){
            System.err.println("そのクラスはアクセスできません");
            System.exit(1);
        }catch(InstantiationException e){
            System.err.println("そのクラスはインスタンス化できません");
            System.exit(1);
        }
 
        s.addAll(Arrays.asList(fakeargs).subList(1,fakeargs.length));
        System.out.println(s);
    }
 
}

出力結果
[Khloe, Kourtney, Kim]

こんなことするくらいだったら、インタフェースや親クラスを使おう!

typeid

サポートサイト Wikidot.com typeid