JAvaのクラス反射メカニズム


一、反射とは何か:
      反射の概念は1982年にSmithによって初めて提案され、主にプログラムが自身の状態や動作にアクセス、検出、修正できる能力を指す.この概念の提出はすぐにコンピュータ科学分野の応用反射性に関する研究を引き起こした.まずプログラム言語の設計分野に採用され,Lispとオブジェクト向けの面で成績を収めた.このうちLEAD/LEAD++,OpenC++,MetaXa,OpenJavaなどは反射機構に基づく言語である.最近,反射機構もウィンドウシステム,オペレーティングシステム,ファイルシステムに応用されている.
      反射自体は新しい概念ではないが,コンピュータ科学は反射概念に新しい意味を与えた.コンピュータ科学の分野では、反射は自己記述と自己制御が可能な応用を指す.すなわち、このようなアプリケーションは、あるメカニズムを用いて、自己動作の記述(self−representation)およびモニタリング(examination)を実現し、自己動作の状態および結果に基づいて、アプリケーションが記述する動作の状態および関連する意味を調整または修正することができる.
二、Javaのクラス反射とは何か:       ReflectionはJavaプログラム開発言語の特徴の一つであり、実行中のJavaプログラムが自身をチェックしたり、「自己確認」したりして、プログラムの内部属性や方法を直接操作することができます.Javaのこの能力は実際のアプリケーションではあまり使われていませんが、他のプログラム設計言語ではこの特性は存在しません.たとえば,Pascal,CあるいはC++では,関数定義に関する情報をプログラムで取得することはできない.
ReflectionはJavaが動的(または準動的)言語と見なされる鍵であり、プログラムが実行期間Reflection APIsでpackage、type parameters、superclass、implemented interfaces、inner classes、outer class、fields、constructors、methods、modifiersを含む既知の名前のclassの内部情報を取得し、実行期間中にinstances、fieldsの内容を変更したり、methodsを呼び出したりします.
三、Javaクラスの反射に必要なクラス:
      Javaのクラス反射に必要なクラスは多くありません.Field、Constructor、Method、Class、Objectです.以下、これらのクラスについて簡単に説明します.
Fieldクラス:クラスまたはインタフェースのプロパティに関する情報と、その動的アクセス権を提供します.反射されるフィールドは、クラス(静的)プロパティまたはインスタンスプロパティであり、反射クラスのプロパティをカプセル化するクラスと見なすことができることを簡単に理解します.
Constructorクラス:クラスの単一の構築方法に関する情報とアクセス権を提供します.このクラスはFieldクラスと異なり,Fieldクラスは反射クラスの属性をカプセル化し,Constructorクラスは反射クラスの構造方法をカプセル化している.
Methodクラス:クラスまたはインタフェース上の個別のメソッドに関する情報を提供します.反映されるメソッドは、抽象メソッドを含むクラスメソッドまたはインスタンスメソッドである可能性があります.このクラスは反射クラスメソッドをカプセル化するためのクラスであることは理解に難くない.
Classクラス:クラスのインスタンスは、実行中のJavaアプリケーションのクラスとインタフェースを表します.列挙は一種であり、注釈はインタフェースである.各配列はクラスオブジェクトとしてマッピングされたクラスに属し、同じ要素タイプと次元数を持つすべての配列がクラスオブジェクトを共有します.
Objectクラス:クラスごとにObjectをスーパークラスとして使用します.すべてのオブジェクト(配列を含む)がこのクラスのメソッドを実装します.
四、Javaの反射類は何ができますか.
       上の多くを見終わって、私はあなたがもううんざりしていると思います.あなたは私があなたの時間を浪費していると思っています.それではいいでしょう.以下、簡単な例で説明します.
       まずJavaの反射メカニズムで何が得られるかを見てみましょう.
       まずクラスを書きます.
import java.awt.event.ActionListener; 
import java.awt.event.ActionEvent; 
class A extends Object implements ActionListener{ 
private int a = 3; 
public Integer b = new Integer(4); 
public A(){} 
public A(int id,String name){} 
public int abc(int id,String name){return 0;} 
public void actionPerformed(ActionEvent e){} 
} 
 
私のクラスに混乱されているかもしれませんが、私が何をしているのか見えません.このクラスを見ないでください.このクラスはテストに使われています.Objectクラスを継承していることを知っています.ActionListener、2つの属性intとInteger、2つの構造方法と2つの方法があります.これで十分です.
次に、Aというクラスを反射クラスとして、過去のAクラスの情報について説明します.まず、反射クラスの属性と属性値について説明します.
import java.lang.reflect.*; 
class B{ 
public static void main(String args[]){ 
A r = new A(); 
Class temp = r.getClass(); 
try{ 
         System.out.println("           "); 
                         Field[] fb  =temp.getFields(); 
for(int j=0;j<fb.length;j++){ 
Class cl = fb[j].getType(); 
System.out.println("fb:"+cl); 
} 

                        System.out.println("         "); 
Field[] fa = temp.getDeclaredFields(); 
                        for(int j=0;j<fa.length;j++){ 
Class cl = fa[j].getType(); 
System.out.println("fa:"+cl); 
} 
                           System.out.println("          "); 
Field f = temp.getDeclaredField("a"); 
f.setAccessible(true); 
Integer i = (Integer)f.get(r); 
System.out.println(i); 
}catch(Exception e){ 
e.printStackTrace(); 
} 
} 

} 
 
ここでは、反射クラス内のすべての共通属性と反射クラス内のすべての属性を取得するためのgetFields()とgetDeclaredFields()の2つの方法を使用します.また、getField(String)メソッドとgetDeclaredField(String)メソッドは、いずれも過去の反射クラスで指定された属性に使用されるメソッドであり、getFieldメソッドは反射クラスに共通する属性しか取得できず、getDeclaredFieldメソッドはすべて取得できることに注意してください.
ここでは、反射クラスのプライベート属性にアクセスする権限があるかどうかを設定するためのFieldクラスのsetAccessibleメソッドも使用されます.trueに設定した場合にのみアクセスできます.デフォルトはfalseです.またFieldクラスにはset(Object AttributeName,Object value)メソッドがあり、指定した属性の値を変更できます.
次に、反射クラスの構造方法について説明します.
import java.lang.reflect.*; 
public class SampleConstructor { 
public static void main(String[] args) { 
A r = new A(); 
printConstructors(r); 
} 

public static void printConstructors(A r) { 
Class c = r.getClass(); 
//         
String className = c.getName(); 
try { 
//           
Constructor[] theConstructors = c.getConstructors(); 
for(int i=0; i<theConstructors.length; i++) { 
//               
Class[] parameterTypes = theConstructors[i].getParameterTypes(); 

System.out.print(className + "("); 

for(int j=0; j<parameterTypes.length; j++) 
System.out.print(parameterTypes[j].getName() + " "); 

System.out.println(")"); 

} 
}catch(Exception e) { 
e.printStackTrace(); 
} 
} 
} 
 
この例は簡単で,getConstructors()メソッドで反射クラスの構造メソッドの集合を取得し,ConstructorクラスのgetParameterType()でその構造メソッドのパラメータを取得しただけである.
次に、反射クラスの親(スーパークラス)とインタフェースを取得します.
import java.io.*; 
import java.lang.reflect.*; 

public class SampleInterface { 
public static void main(String[] args) throws Exception { 
A raf = new A(); 
printInterfaceNames(raf); 
} 

public static void printInterfaceNames(Object o) { 
Class c = o.getClass(); 
//         
Class[] theInterfaces = c.getInterfaces(); 
for(int i=0; i<theInterfaces.length; i++) 
System.out.println(theInterfaces[i].getName()); 
//        (  ) 
Class theSuperclass = c.getSuperclass(); 
System.out.println(theSuperclass.getName()); 
} 
} 
 
この例も簡単で、ClassクラスのgetInterfaces()メソッドで反射クラスのすべてのインタフェースを取得するだけで、インタフェースは複数ある可能性があるため、1つのClass配列を返します.反射クラスの親(スーパークラス)をgetSuperclass()メソッドで取得します.クラスは1つのクラスからしか継承できないため、クラスオブジェクトを返します.
次に、反射クラスの方法について説明します.
import java.lang.reflect.*; 
public class SampleMethod { 

public static void main(String[] args) { 
A p = new A(); 
printMethods(p); 
} 

public static void printMethods(Object o) { 
Class c = o.getClass(); 
String className = c.getName(); 
Method[] m = c.getMethods(); 
for(int i=0; i<m.length; i++) { 
//          
System.out.print(m[i].getReturnType().getName()); 
//      
System.out.print(" "+m[i].getName()+"("); 
//        
Class[] parameterTypes = m[i].getParameterTypes(); 
for(int j=0; j<parameterTypes.length; j++){ 
System.out.print(parameterTypes[j].getName()); 
if(parameterTypes.length>j+1){ 
System.out.print(","); 
} 
} 

System.out.println(")"); 
} 

} 

} 
 
この例は難しくありません.親から継承する方法を含む反射クラスのすべての方法を得ただけです.次に、メソッドの戻りタイプ、メソッド名、およびメソッドパラメータを取得します.
次に振り返ってみましょう.反射クラスの属性、構造方法、親クラス、インタフェース、方法を取得しましたが、これらのものは私たちに何をすることができますか?!
次に、Javaの反射クラスが何ができるかを説明する比較的完全な例を書きます!!
import java.lang.reflect.Constructor; 
import java.lang.reflect.Method; 

public class LoadMethod { 
public Object Load(String cName,String MethodName,String[] type,String[] param){ 
Object retobj = null; 
try { 
        //     Java  
            Class cls = Class.forName(cName); 
            
            //          
            Constructor ct = cls.getConstructor(null); 
            Object obj = ct.newInstance(null); 
            
            //            
            Class partypes[] = this.getMethodClass(type); 
            
            //             
            Method meth = cls.getMethod(MethodName, partypes); 
            
            //         
            Object arglist[] = this.getMethodObject(type,param); 

            //              Object   
            retobj= meth.invoke(obj, arglist); 

        } 
        catch (Throwable e) { 
            System.err.println(e); 
        } 
return retobj; 
} 

//      Class[]    
public Class[] getMethodClass(String[] type){ 
Class[] cs = new Class[type.length]; 
for (int i = 0; i < cs.length; i++) { 
if(!type[i].trim().equals("")||type[i]!=null){ 
if(type[i].equals("int")||type[i].equals("Integer")){ 
cs[i]=Integer.TYPE; 
}else if(type[i].equals("float")||type[i].equals("Float")){ 
cs[i]=Float.TYPE; 
}else if(type[i].equals("double")||type[i].equals("Double")){ 
cs[i]=Double.TYPE; 
}else if(type[i].equals("boolean")||type[i].equals("Boolean")){ 
cs[i]=Boolean.TYPE; 
}else{ 
cs[i]=String.class; 
} 
} 
} 
return cs; 
} 

//    Object[]    
public Object[] getMethodObject(String[] type,String[] param){ 
Object[] obj = new Object[param.length]; 
for (int i = 0; i < obj.length; i++) { 
if(!param[i].trim().equals("")||param[i]!=null){ 
if(type[i].equals("int")||type[i].equals("Integer")){ 
obj[i]= new Integer(param[i]); 
}else if(type[i].equals("float")||type[i].equals("Float")){ 
obj[i]= new Float(param[i]); 
}else if(type[i].equals("double")||type[i].equals("Double")){ 
obj[i]= new Double(param[i]); 
}else if(type[i].equals("boolean")||type[i].equals("Boolean")){ 
obj[i]=new Boolean(param[i]); 
}else{ 
obj[i] = param[i]; 
} 
} 
} 
return obj; 
} 
} 
 
これは私が仕事で書いたJavaが実行時に指定したクラスをロードし、指定したメソッドを呼び出す小さな例です.ここにはmainの方法がないので、自分で書いてもいいです.
Loadメソッドが受信する5つのパラメータは,Javaのクラス名,メソッド名,パラメータのタイプ,パラメータの値である.
終了:
Java言語反射は、ダイナミックリンクプログラムコンポーネントの多機能メソッドを提供します.これにより、ターゲットクラスを事前にハードコーディングすることなく、任意のクラスのオブジェクトを作成および制御できます.これらのプロパティにより、反射は、非常に一般的な方法でオブジェクトとコラボレーションするライブラリの作成に特に適しています.Java reflectionは、クラスとデータ構造が名前で動的に関連情報を取得し、実行中のプログラムでこれらの情報を操作できるようにするのに役立ちます.Javaのこの特性は非常に強く、C、C++、Fortran、Pascalなど、他の一般的な言語では備えられていません.
しかし、反射には2つの欠点がある.1つ目はパフォーマンスの問題です.フィールドおよびメソッドへのアクセスでは、直接コードよりも反射が遅くなります.パフォーマンスの問題の程度は、プログラムで反射をどのように使用するかによって異なります.プログラムの実行に比較的少ない部分である場合、遅いパフォーマンスは問題ではありません.テストで最悪の場合のタイムチャートに表示される反射動作は数マイクロ秒しかかかりません.パフォーマンスの重要なアプリケーションのコアロジックで使用される場合にのみ、パフォーマンスの問題を反射することが重要になります.