JAva反射入門


一、反射の概念:
反射の概念は1982年にSmithによって初めて提案され、主にプログラムが自身の状態や動作にアクセス、検出、修正できる能力を指す.この概念の提出はすぐにコンピュータ科学分野の応用反射性に関する研究を引き起こした.まずプログラム言語の設計分野に採用され,Lispとオブジェクト向けの面で成績を収めた.このうちLEAD/LEAD++,OpenC++,MetaXa,OpenJavaなどは反射機構に基づく言語である.最近,反射機構もウィンドウシステム,オペレーティングシステム,ファイルシステムに応用されている. 
反射自体は新しい概念ではなく、光学中の反射概念を連想させる可能性があります.コンピュータ科学は反射概念に新しい意味を与えていますが、現象的には、いくつかの共通点があり、これらは私たちの理解に役立ちます.コンピュータ科学の分野では、反射は自己記述と自己制御が可能な応用を指す.つまり、このような応用は,あるメカニズムを用いて自己挙動の記述(self−representation)とモニタリングを実現する.(examination)は、自身の行為の状態と結果に基づいて、記述された行為の状態と関連する意味を調整または修正することができる.一般的な反射概念と比較して、コンピュータ科学分野の反射は反射そのものだけでなく、反射結果に対する措置も含まれていることがわかる.反射機構を採用したすべてのシステム(すなわち、反射システム)システムの実現をより開放的にすることが望ましい.反射メカニズムを実現したシステムはすべて開放性を持っていると言えるが、開放性を持ったシステムは必ずしも反射メカニズムを採用しているとは限らず、開放性は反射システムの必要条件である.一般的に、反射システムは開放性条件を満たす以外に原因接続を満たさなければならない(Causally-connected).理由接続とは、反射システムの自己記述の変更が、システムの下位層の実際の状態や動作に直ちに反映される場合を指し、逆も同様である.開放性と原因接続は反射システムの2つの基本要素である.
Javaでは、反射は強力なツールです.これにより、コンポーネント間のソース代表リンクを必要とせずに実行時にアセンブリできる柔軟なコードを作成できます.反射により、ソースコードで選択したクラスコラボレーションのコードではなく、JVMにロードされたクラスの内部情報にプログラムコードがアクセスできるようになります.これにより、反射は柔軟なアプリケーションを構築する主なツールになります.しかし、不適切な使用では反射のコストが高いことに注意してください.
二、Javaにおけるクラス反射:
ReflectionはJavaプログラム開発言語の特徴の一つであり、実行中のJavaプログラムが自身をチェックしたり、「自己確認」したりして、プログラムの内部属性を直接操作することができます.Javaのこの能力は実際のアプリケーションではあまり使われていないかもしれませんが、他のプログラム設計言語ではこの特性は存在しません.たとえば,Pascal,CあるいはC++では,関数定義に関する情報をプログラムで取得することはできない.
1.検査類:
1.1 reflectionの動作メカニズム
反射は、比較的白い言葉で要約すると、名前でオブジェクト(クラス、属性、方法)を得ることができる技術です.たとえば、クラス名を使用してクラスのインスタンスを生成できます.メソッド名が分かれば、このメソッドを呼び出すことができます.属性名が分かれば、この属性の値にアクセスできます.
反射の使い方をより直感的に理解するために、2つの例を書きます.
//クラス名でクラスを構築するインスタンスClass cls_str = Class.forName( "java.lang.String" );// JDBCを使ってデータベースにアクセスした人はみなJ Object str=cls_を使ったことがあるので、よく知っています.str.newInstance();// String str=new String()に相当します.
//メソッド名でメソッドString methodName=「length」を呼び出します.Method m = cls_str.getMethod(methodName, null ); System.out.println( "length is "+ m.invoke(str, null ));// Systemに相当する.out.println(str.length());
次の簡単な例を考えて、reflectionがどのように働いているかを見てみましょう.
import java.lang.reflect.*;
public class DumpMethods {
    public static void main(String args[]) {
        try {
            Class c = Class.forName(args[0]);
            Method m[] = c.getDeclaredMethods();
            for (int i = 0; i < m.length; i++)
                System.out.println(m[i].toString());
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

次の文で実行します.
java DumpMethods
結果は次のように出力されます.
public int java.lang.String.hashCode() public int java.lang.String.compareTo(java.lang.String) public int java.lang.String.compareTo(java.lang.Object)
****************
public static java.lang.String java.lang.String.valueOf(char)
 
これでjavaがリストされます.util.Stringクラスのメソッド名と、その制限子と戻りタイプ.
このプログラムはClassを使います.forNameは指定したクラスを読み込み、getDeclaredMethodsを呼び出してクラスで定義されたメソッドのリストを取得します.java.lang.reflect.Methodsは、クラス内の単一のメソッドを記述するために使用されるクラスです.
1.2 Javaクラスの反射における主な方法
次の3つのコンポーネントのいずれかについて、関数、フィールド、メソッドを構築するjava.lang.Classは4つの独立した反射呼び出しを提供し、異なる方法で情報を得る.呼び出しはすべて標準フォーマットに従います.次に、コンストラクション関数を検索するための反射呼び出しのセットを示します.
l Constructor getConstructor(Class[]params)--特殊なパラメータタイプを使用した共通構造関数を取得します.
l Constructor[]getConstructors()--クラスのすべての共通構造関数を取得
l Constructor getDeclaredConstructor(Class[]params)--アクセス・レベルに関係なく、特定のパラメータ・タイプを使用するコンストラクション関数を取得します.
l Constructor[]getDeclaredConstructors()--アクセスレベルに関係なくクラスのすべてのコンストラクション関数を取得します.
フィールド情報を取得するClass反射呼び出しは、構造関数にアクセスするための呼び出しとは異なり、パラメータタイプ配列ではフィールド名が使用されます.
l Field getField(String name)--名前付きの共通フィールドを取得
l Field[]getFields()--クラスのすべての共通フィールドを取得
l Field getDeclaredField--クラス宣言の名前付きフィールドを取得
l Field[]getDeclaredFields()--クラス宣言のすべてのフィールドを取得
メソッド情報を取得するための関数:
l Method getMethod(String name,Class[]params)--特定のパラメータタイプを使用して、名前付きの共通メソッドを取得します.
l Method[]getMethods()--クラスのすべての共通メソッドを取得
l Method getDeclaredMethod(String name,Class[]params)--クローズアップされたパラメータタイプを使用して、クラス宣言の名前付けを取得する方法
l Method[]getDeclaredMethods()--クラス宣言を取得するすべての方法
 
1.3 Reflectionの使用を開始します.
Methodのようなreflection用のクラスはjavaで使用できます.lang.relfectパッケージに見つかりました.これらのクラスを使用するには、3つのステップに従う必要があります.最初のステップは、操作したいクラスのjavaを取得することです.lang.Classオブジェクト.実行中のJavaプログラムではjava.lang.Classクラスは、クラスやインタフェースなどを記述します.
次に、Classオブジェクトを取得する方法の1つを示します.
Class c = Class.forName("java.lang.String");
この文はStringクラスのクラスオブジェクトを得ます.次の文のような別の方法があります.
Class c = int.class;
または
Class c = Integer.TYPE;
基本タイプのクラス情報を取得できます.後者の方法では、Integerなどの基本タイプのパッケージクラスで予め定義されたTYPEフィールドにアクセスします.
第2のステップは、getDeclaredMethodsのようなメソッドを呼び出し、クラスで定義されたすべてのメソッドのリストを取得することである.
この情報を取得すると、次のコードのようにreflection APIを使用してこれらの情報を操作する第3のステップが実行されます.
Class c = Class.forName("java.lang.String");
Method m[] = c.getDeclaredMethods();
System.out.println(m[0].toString());
Stringで定義された最初のメソッドのプロトタイプがテキストで印刷されます.
2.処理対象:
debuggerのような開発ツールを作成するには、filed valuesを見つける必要があります.以下は3つのステップです.
a.Classオブジェクトを作成するb.getFieldによってFieldオブジェクトを作成するc.Fieldを呼び出す.getXXX(Object)の方法(XXXはInt,Float等である、対象であれば省略する;Objectはインスタンスを指す).
例:
import java.lang.reflect.*;
import java.awt.*;
class SampleGet {
   public static void main(String[] args) {
      Rectangle r = new Rectangle(100, 325);
      printHeight(r);
   }
   static void printHeight(Rectangle r) {
      Field heightField;
      Integer heightValue;
      Class c = r.getClass();
      try {
        heightField = c.getField("height");
        heightValue = (Integer) heightField.get(r);
        System.out.println("Height: " + heightValue.toString());
      } catch (NoSuchFieldException e) {
          System.out.println(e);
      } catch (SecurityException e) {
          System.out.println(e);
      } catch (IllegalAccessException e) {
          System.out.println(e);
      }
   }
}