リフレクションは、"自己検査を"Javaプログラムは、それ自体をチェックしたり、実行できるようにする特性のJavaプログラミング言語の一つである内部動作の手順に属性を直接することができます。例えば、それは各メンバーと表示のJavaクラス名を取得することができます。
しかし、多くのJavaは、この機能の実用的なアプリケーションで使用される可能性がありますされていない他のプログラミング言語では、この機能は単に、存在しません。たとえば、パスカル、CまたはC + +プログラムの関連情報の関数の定義を取得する方法がある。
JavaBeanは、実用化を反映して、それはソフトウェアコンポーネントを操作する視覚化ツールをすることができます。これらのツールは、リフレクションを介して動的にロードされ、プロパティのJavaコンポーネント(クラス)を取得します。
1。簡単な例
、次の簡単な例を考えて私たちが見てみましょうどのように仕事の反射。
インポートが.* java.lang.reflectの;
パブリッククラスDumpMethods {
します。public static voidは、メイン{(文字列は[]を引数)
{しよう
クラスc = Class.forNameを(引数[0]);
メソッドm [] = c.getDeclaredMethods();
(;一未満m.length; i + +のint型一= 0)
System.out.println(メートル[i]のToStringメソッド());
}キャッチ(Throwableの電子){
します。System.err.println(e)の;
}
}
}
次のようにステートメントが実行されます:
javaのDumpMethodsのjava.util.Stack
これは、結果の出力は、です:
公共java.lang.Objectのjava.util.Stack.push(java.lang.Object)メソッド
公共同期java.lang.Objectのjava.util.Stack.pop()
公共同期java.lang.Objectのjava.util.Stack.peek()
パブリックブールjava.util.Stack.empty()
公共同期のint java.util.Stack.search(java.lang.Object)メソッド
これは、各メソッドjava.util.Stackクラスとその修飾子および戻り値の型の名前が表示されます。
このプログラムは、このクラスを取得するためにgetDeclaredMethodsを呼び出して、指定されたクラスをロードするClass.forNameを使用する方法のリストを定義します。java.lang.reflect.Methodsは、クラスのクラスの単一のメソッドを記述するために使用されています。
2は反射を開始
クラスのリフレクションの場合、メソッドなど、java.lang.relfectパッケージで見つけることができます。ときにこれらのクラスを使用して3つの手順に従う必要があります:最初の手順は、java.lang.Classオブジェクトを操作するクラスを取得することです。java.lang.Classクラスと、Javaプログラムで実行されているクラスやインターフェイスを記述する。
ここではクラスオブジェクトのメソッドを取得することです:
クラスc = Class.forNameを("java.lang.String"など);
このステートメントは、Stringクラスのクラスオブジェクトを取得します。別の方法は、次のステートメントのように、ある:
クラスc = int.class;
または
クラスc = Integer.TYPEの;
彼らは、クラス情報の基本的な種類が表示されます。後者の方法のいずれかをご覧ください事前に定義されたTYPEフィールドパッケージ(Integerなど)の基本的なタイプです。
第二のステップは、クラスのリストで定義されたすべてのメソッドを取得するためにgetDeclaredMethodsなどのメソッドを呼び出すことです。
完了したら、この情報を取得している、3番目の手順を行うことができる - と、次のコードなどの情報を操作するためのリフレクションAPIを使用する:
クラスc = Class.forNameを("java.lang.String"など);
メソッドm [] = c.getDeclaredMethods();
System.out.println(メートル[0] ToStringメソッド());
これは、最初のプロトタイプで定義されたテキスト文字列のメソッドとして印刷されます。
例を提供するためにリフレクションを使用して特定のアプリケーションに対処するための3つの手順は、以下の例では。
アナログinstanceof演算子
クラス情報を取得した後、通常、次のステップは、いくつかの基本的な問題のクラスのオブジェクトに解決することです。たとえば、Class.isInstanceメソッドはinstanceof演算子をシミュレートするために使用することができます:
クラスA {
}
パブリッククラスインスタンス1 {
します。public static voidは、メイン{(文字列は[]を引数)
{しよう
クラス分類= Class.forNameを("");
ブール値b1は= cls.isInstance(新しいInteger(37));
System.out.println(b1)と;
ブール値b2は= cls.isInstance(新しいA());
System.out.println(b2)の;
}キャッチ(Throwableの電子){
します。System.err.println(e)の;
}
}
}
この例では、クラスAのオブジェクトのクラスを作成し、確認するいくつかのオブジェクトには、Aのインスタンスであるかどうかを整数は、(37)ではなく、新たな()になります。
3クラスのメソッドを検索するには
クラスには、どのようなメソッドは、これは非常に基本的な反射の非常に貴重な使用が定義されて下さい。次のコードは、この状況を実現:
インポートが.* java.lang.reflectの;
パブリッククラスmethod1に{
プライベートint型のf1(オブジェクトpは、int型x)はNullPointerExceptionを{スロー
(p == null)の場合
新しいNullPointerExceptionを()をスローします。
xを返す。
}
します。public static voidは、メイン{(文字列は[]を引数)
{しよう
クラスのcls = Class.forNameをは("法1");
メソッドmethlist [] = cls.getDeclaredMethods();
{(;一未満methlist.length i + +のint型一= 0)
メソッドm = methlist [i]の;
System.out.println("名前="+ m.getName());
System.out.println("赤緯クラス="+ m.getDeclaringClass());
クラスpvec [] = m.getParameterTypes();
(; jとpvec.length; J + +のint型jが= 0)
System.out.println("パラメータ#"+ jは""+ pvec [j]の);
クラスevec [] = m.getExceptionTypes();
(; jとevec.length; J + +のint型jが= 0)
System.out.println("#大口"+ jは""+ evec [j]の);
System.out.println("戻り値の型="+ m.getReturnType());
System.out.println ("-----");
}
}キャッチ(Throwableの電子){
します。System.err.println(e)の;
}
}
}
このプログラムは、最初のパブリックメソッド、protectedメソッドは、パッケージprivateメソッドやメソッドなどの各メソッドを記述するクラスで定義されているMethodオブジェクト、一連のを取得するためにgetDeclaredMethodsを呼び出して、法1クラスの説明を入手してください。あなたはgetMethods getDeclaredMethodsを交換するプログラムを使用する場合は、すべての継承されたメソッドを取得することができます。
メソッドは、オブジェクトのリストを取得するために、これらのメソッドのパラメータは、例外の型と戻り値の型困難ではないの種類を表示します。これらの型は、基本的な型またはクラス型が、指定された順序でオブジェクトのクラスを記述することができます。
出力は次のようにです:
名前= f1は
赤緯クラス=クラスmethod1に
パラメータ#0クラスであるjava.lang.Object
パラメータ#1 int型
大口#0クラスjava.lang.NullPointerExceptionが
戻り値の型= int型
-----
名前=メイン
赤緯クラス=クラスmethod1に
パラメータ#0クラス[Ljava.lang.String;
戻り値の型=無効
4。コンストラクタの情報を取得する
などの同様のメソッドの使用については、上記の使用のためのクラスのコンストラクタ:
インポートが.* java.lang.reflectの;
パブリッククラスconstructor1 {
公共constructor1(){
}
(int型私は、ダブルD){constructor1保護
}
します。public static voidは、メイン{(文字列は[]を引数)
{しよう
クラスのcls = Class.forNameをは("constructor1");
コンストラクタctorlist [] = cls.getDeclaredConstructors();
{(;一未満ctorlist.length i + +のint型一= 0)
コンストラクタのctは= ctorlist [i]の;
System.out.println("名前="+ ct.getName());
System.out.println("赤緯クラス="+ ct.getDeclaringClass());
クラスpvec [] = ct.getParameterTypes();
(; jとpvec.length; J + +のint型jが= 0)
System.out.println("パラメータ#"+ jは""+ pvec [j]の);
クラスevec [] = ct.getExceptionTypes();
(; jとevec.length; J + +のint型jが= 0)
System.out.println("#大口"+ jは""+ evec [j]の);
System.out.println ("-----");
}
}キャッチ(Throwableの電子){
します。System.err.println(e)の;
}
}
}
コンストラクタは、型を返すしないため、情報の種類を取り戻すことでしたこの場合は、そうです。
実行結果:
名前= constructor1
赤緯クラス=クラスconstructor1
-----
名前= constructor1
赤緯クラス=クラスconstructor1
パラメータ#0 int型
パラメータ#1ダブル
5クラスのフィールド(ドメイン)の場合
クラスは、データフィールドは、また、この事乾燥に次のコードを可能かを定義して下さい:
インポートが.* java.lang.reflectの;
パブリッククラスフィールド1 {
プライベートdは二重;
のpublic static finalのint i = 37;
文字列は、="テスト"だ。
します。public static voidは、メイン{(文字列は[]を引数)
{しよう
クラスのcls = Class.forNameをは("フィールド1");
フィールドのフィールドリスト[] = cls.getDeclaredFields();
{(;一未満fieldlist.length i + +のint型一= 0)
フィールドには、FLDに= [i]のフィールドリスト;
System.out.println("名前="+ fld.getName());
System.out.println("赤緯クラス="+ fld.getDeclaringClass());
System.out.println("タイプ="+ fld.getType());
int型モッズ= fld.getModifiers();
System.out.println("修飾子="+ Modifier.toString(モッズ));
System.out.println ("-----");
}
}キャッチ(Throwableの電子){
します。System.err.println(e)の;
}
}
}
この例では、非常に前の例と似ています。たとえば、修飾子は、それはまた、反射クラスです新しいものを使用して、"プライベートint型"のように、フィールドを記述するために使用される修飾子のメンバー。これらの修飾子は、整数自体が記載された使用は、文字列(などの"最終"の前に、"静的")のための"公式"の説明に戻りますModifier.toString。このプログラムの出力は:
名前= dは
赤緯クラス=クラスのフィールド1
タイプ=ダブル
修飾子=プライベート
-----
名前= iの
赤緯クラス=クラスのフィールド1
タイプは、= int型
修飾子=のpublic static final
-----
名前は=だ
赤緯クラス=クラスのフィールド1
型=クラスjava.lang.String
修飾子=
状況やフィールドを取得する方法を見て、フィールド情報の現在の状態(getDeclaredFields)のクラス、または親クラスがフィールド(getFields)が定義されて得ることができる場合にのみ達成することができます。
6。メソッドのメソッド名によると、
ここにテキストは、例外なく、すべての例とどのようにクラスに関する情報を入手してください。また、名を指定しての実施方法など、いくつかの他のものを行なうためには、リフレクションを使用することができます。次の例は、次を示します:
インポートが.* java.lang.reflectの;
パブリッククラス法2 {
公共intは(int型をint b)の追加{
返す+ bの;
}
します。public static voidは、メイン{(文字列は[]を引数)
{しよう
クラスのcls = Class.forNameをは("法2");
クラスには、[] =新しいクラス[2] partypes;
partypesは、[0] = Integer.TYPEのを。
partypesは、[1] = Integer.TYPEのを。
メソッドmeth = cls.getMethod("追加"、partypes);
法2 methobj =新しい法2();
オブジェクトの引数リスト[] =新しいオブジェクト[2];
引数リスト[0] =新しいInteger(37);
引数リスト[1] =新しいInteger(47);
オブジェクトretobj = meth.invoke(methobj、引数リスト);
整数retvalを=(整数)retobj;
System.out.println(retval.intValue());
}キャッチ(Throwableの電子){
します。System.err.println(e)の;
}
}
}
どこかにプログラムの実装では、メソッドを実行する必要性を認識される場合は、このメソッドは、指定されたで実行されているプログラム(たとえば、JavaBeanの開発環境は、このような事をするでしょう)、上記のプロシージャの名前です。どのように行う方法を示しています。
上記の例は、2つの整数パラメータを見つけるために使用さGetMethodメソッドを追加呼ばれる。Findメソッドを、対応するMethodオブジェクトを、それを実行するには、右のオブジェクトのインスタンスを作成します。メソッドの実装は、必要が上記の例では、は、それぞれ37と47は、2つのIntegerオブジェクトのラップ整数パラメータの一覧を提供しています。実行メソッドは、整数は84の戻り値をカプセル化し、同じオブジェクトを返すことです。
図7は、新しいオブジェクトを作成するには
それはコンストラクタの実装は、新しいオブジェクトが(メモリの割り当てを含むオブジェクトを作成するプロセス正確には、オブジェクトを作成)を作成することを意味するので、コンストラクタは、あなたは、メソッドの実装を好きではない。したがって、次のように、前の例の最も類似した例:
インポートが.* java.lang.reflectの;
パブリッククラスconstructor2 {
公共constructor2(){
}
公共constructor2は(int型をint b)は{
System.out.println("="+ +の"b ="+ b)の
}
します。public static voidは、メイン{(文字列は[]を引数)
{しよう
クラスのcls = Class.forNameをは("constructor2");
クラスには、[] =新しいクラス[2] partypes;
partypesは、[0] = Integer.TYPEのを。
partypesは、[1] = Integer.TYPEのを。
コンストラクタのCT = cls.getConstructor(partypes);
オブジェクトの引数リスト[] =新しいオブジェクト[2];
引数リスト[0] =新しいInteger(37);
引数リスト[1] =新しいInteger(47);
オブジェクトretobj = ct.newInstance(引数リスト);
}キャッチ(Throwableの電子){
します。System.err.println(e)の;
}
}
}
指定されたパラメータの型によると、適切なコンストラクタを見つけるために、それが新しいオブジェクトのインスタンスを作成し、実行してください。このメソッドは、動的に非常に貴重な時間を、コンパイル時にオブジェクトを作成するのではなく、オブジェクトを作成するために、実行時に使用することができます。
8フィールド(フィールド)の値を変更します。
オブジェクトの有用な反射が値のデータフィールドを変更することもあります。実行中のプログラムからの反射は、フィールドの名前でオブジェクトを検索し、それを変更するには、この点を説明するには、次の例:
インポートが.* java.lang.reflectの;
パブリッククラスフィールド2 {
公共dは二重;
します。public static voidは、メイン{(文字列は[]を引数)
{しよう
クラスのcls = Class.forNameをは("フィールド2");
フィールドには、("d"を)= cls.getFieldをFLDに。
field2のf2obj =新しいフィールド2();
System.out.println("dは="+ f2obj.d);
(f2obj、12.34)fld.setDouble;
System.out.println("dは="+ f2obj.d);
}キャッチ(Throwableの電子){
します。System.err.println(e)の;
}
}
}
この例では、フィールドの値は、dは12.34で変更されています。
9。アレイを使用すると、
この資料では、最終的な操作の反射は、使用の配列を作成することです説明しています。Java言語での配列は、特別なクラス型は、配列の参照がオブジェクト参照を割り当てることができます。参照するには、以下の例を見てどのように配列の仕事:
インポートが.* java.lang.reflectの;
パブリッククラス配列1 {
します。public static voidは、メイン{(文字列は[]を引数)
{しよう
= Class.forNameを("java.lang.String"など)クラスのcls;
オブジェクトのARRは= Array.newInstance(clsの、10);
Array.setは(ARRの、5、"これはテストです");
文字列は、=(String)をArray.getを(ARRは、5)だ。
System.out.println(秒);
}キャッチ(Throwableの電子){
します。System.err.println(e)の;
}
}
}
10台のケースでは、値を代入された文字列の最初の5つの位置の長さの文字列の配列を作成し、最終的に配列から文字列を取得し、それを印刷してください。
次のコードでは、より複雑な例を提供しています:
インポートが.* java.lang.reflectの;
パブリッククラス配列2 {
します。public static voidは、メイン{(文字列は[]を引数)
int型が暗く=新しいint []を{5、10、15} [];
オブジェクトARRは= Array.newInstance(Integer.TYPEの、暗く);
オブジェクトarrobj = Array.get(ARRは、3);
= arrobj.getClass()クラスのcls GetComponentType();
System.out.println(CLS)に;
arrobj = Array.get(arrobj、5);
Array.setInt(arrobj、10、37);
int型arrcastの[][][] =(int型[][][])のARRの;
System.out.println(arrcast [3] [5] [10]);
}
}
例では、作成する5 × 10 × 15の整数配列、および[3] [5] [10] 37の要素の値が割り当てられます。多次元配列は、実際に配列の配列であることに注意して、たとえば、最初のArray.get後、arrobjは10 × 15の配列です。次に、要素、すなわち、のいずれかを、長さ15の配列を取得し、割り当ての最初の10個の要素のArray.setIntを使用しています。
メモの作成時に配列型は、その型を認識しない、コンパイル時に、動的であることを確認します。