Java反射学習(一)

6648 ワード

译文1アドレス问题主はJavaを习ったばかりの顷からJava反射を知っていましたが、実际の开発で使われていることは多くないので、まだ深く理解していません.最近、社内フレームワークのソースコードを见ていると、Java反射によって多くの机能が実现されていることがわかりました.この文章は主にJava反射の基本的な知識を紹介して、自分で後で調べることができます.まずJava反射の定義をご紹介します
JAVA反射機構は運転状態において、いずれのクラスに対しても、このクラスのすべての属性と方法を知ることができる.任意のオブジェクトに対して、その任意のメソッドを呼び出すことができます.このような動的に取得された情報および動的にオブジェクトを呼び出す方法の機能をjava言語の反射メカニズムと呼ぶ.Java反射の核心は、JVMが実行時にクラスを動的にロードするか、メソッド/アクセス属性を呼び出すことです.コンパイル中に実行するオブジェクトが誰なのかを知る必要はありません.Java反射の実際の操作オブジェクトは.classファイル(バイトコードファイル)です.
Classオブジェクトを取得
1.ClassクラスのforNameスタティックメソッドにより、JDBC開発でよく使用されるこのメソッドのロードドライバ
Class> c1 = Class.forName("java.lang.Integer");

2.オブジェクトを呼び出すgetClass()メソッド
Integer i1 = 1;
Class> c2 = i1.getClass();

3.直接取得クラスのclass
Class> c3 = Integer.class;

クラスのインスタンスかどうかを判断する
クラスのインスタンスかどうかを判断するには、一般的にinstanceofのキーワードが使用されます.また、次のコードのように、ClassオブジェクトのisInstance()の方法で判断することもできます.
Object obj = "Java";
//   instanceof   
System.out.println(obj instanceof  String);
//   isInstance  
System.out.println(String.class.isInstance(obj));
isInstance()メソッドはnativeメソッドであり、そのメソッド署名は以下の通りである.
public native boolean isInstance(Object obj);

インスタンスの作成
Java反射によるオブジェクトの作成には2つの方法があります.1.ClassオブジェクトのnewInstanceメソッドによるClassオブジェクトに対応するインスタンスの作成
Class> c = String.class;
Object s = c.newInstance();

2.Classオブジェクトから指定したConstructorオブジェクトを取得してから、ConstructorオブジェクトのnewInstanceメソッドを呼び出してオブジェクトのインスタンスを作成します.これにより、コンストラクタを指定してオブジェクトを構築できます.
Class> cc = String.class;
Constructor constructor =  cc.getConstructor(String.class);
Object ss = constructor.newInstance("Java");
System.out.println(ss);

クラス名と変数の取得
ClassオブジェクトのgetName()を直接呼び出すとクラス名(パッケージを含む)が取得されます.
Class> c = String.class;
System.out.println(c.getName());

クラスの変数を取得するには、次の2つの方法があります.1.クラスオブジェクトのgetFieldメソッドでクラスのすべての変数を取得します.getField()は、そのクラスとその親のすべての公有変数を取得することに注意してください.
// Book      
Class> c = Book.class;
Field[] fields = c.getFields();


2.オブジェクトのプライベート変数を取得する場合は、アクセス権に関係なくクラスのすべての変数を返すgetDeclaredFields()メソッドを使用します.
// Book      
Class> c = Book.class;
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
    //       
    System.out.println(field.getModifiers());
    //          
    System.out.println(field.getType() + " " + field.getName());
}

取得方法
クラスオブジェクトを取得する方法には、主に次の方法があります.1.getDeclaredMethodsメソッドは、共通、保護、デフォルトアクセス、およびプライベートメソッドを含むクラスまたはインタフェース宣言を返すすべてのメソッドですが、継続的なメソッドは含まれません.
public Method[] getDeclaredMethods() throws SecurityException

2.getMethodsは、クラスのすべての共通メソッドおよび継続的なクラス共通メソッドを返す
public Method[] getMethods() throws SecurityException 

3.getMethodは、メソッド名の最初のパラメータと、メソッドパラメータに対応するClassオブジェクトの後のパラメータの特定のメソッドを返します.
public Method getMethod(String name, Class>... parameterTypes)

Classオブジェクトの特定の列を取得
Class> cc = Book.class;
Method[] methods = cc.getMethods();
for (Method method : methods) {
    //            (Modifiers:   )
    int modifiers = method.getModifiers();
    System.out.print(Modifier.toString(modifiers) + " ");
    //             
    Class returnType = method.getReturnType();
    System.out.print(returnType.getName() + " " + method.getName() + "( ");
    //            
    Parameter[] parameters = method.getParameters();
    for (Parameter parameter: parameters) {
        System.out.print(parameter.getType().getName() + " " + parameter.getName() + ",");
    }
    //            
    Class[] exceptionTypes = method.getExceptionTypes();
    if (exceptionTypes.length == 0){
        System.out.println(" )");
    } else {
        for (Class c : exceptionTypes) {
            System.out.println(" ) throws " + c.getName());
        }
    }
}

コンストラクタの取得getConstructor法によりClassオブジェクトのコンストラクタを取得することができ、具体的な例は前述の作成例で説明したが、ここではこれ以上説明しない
呼び出し方法
クラスからメソッドを取得すると、invoke()メソッドでこのメソッドを呼び出すことができます.invokeメソッドの署名は次のとおりです.
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException

invokeの具体例:
public class Client {
    public static void main(String[] args) throws Exception {
        Class> c = Calculation.class;
        Object obj = c.newInstance();
        Method method = c.getMethod("add", int.class, int.class);
        int res = (int) method.invoke(obj, 1, 2);
        System.out.println(res);
    }
}
class Calculation {
    public int add(int x, int y) {
        return x + y;
    }
}

注釈の取得
まず注釈を紹介します.注釈はJava 5の新しい特性で、コードに挿入された注釈またはメタデータです.これらの注記情報は、コンパイル時にプリコンパイルツールを使用して処理してもよいし、実行時にJava反射メカニズムを使用して処理してもよい.注記は次の4つに分けられます.
  • 類注記
  • 方法注釈
  • 変数注記
  • パラメータ注釈紙面制限のため、ここでは取得クラスの注釈のみを紹介し、他の注釈の取得はJava Reflection(8):注釈
  • を参照することができる.
    public class Client {
        public static void main(String[] args) throws Exception {
            Class> c = Calculation.class;
            //       
            // Annotation[] annotations = c.getAnnotations();
            //     MyAnnotation  
            Annotation annotation = c.getAnnotation(MyAnnotation.class);
            if (annotation instanceof MyAnnotation) {
                MyAnnotation myAnnotation = (MyAnnotation) annotation;
                System.out.println(myAnnotation.id());
                System.out.println(myAnnotation.desc());
            }
        }
    }
    
    @MyAnnotation(id ="1", desc = "calc")
    class Calculation {
        public int add(int x, int y) {
            return x + y;
        }
    }
    
    //      
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface MyAnnotation {
        public String id();
        public String desc();
    }
    

    Java反射用途
    上記ではjava反射の基本的な使い方を紹介していますが、業務開発では確かに反射はあまり使われませんが、優れたフレームワークは必然的に反射を使って多くの複雑な機能を実現します.例えばSpringのIOC(制御反転)、beanのxmlファイルを解析することによって、Springは運行期間中にxml構成に基づいてJava反射によって相応のbeanを生成し、Spring容器に入れます.
    Java反射機能
  • オブジェクトのクラス情報を取得する.
  • クラスのアクセス修飾子、メンバー、メソッド、構築メソッド、およびスーパークラスの情報を取得する.
  • .
  • インタフェースに属する定数とメソッド宣言を検出する.
  • プログラムが実行されるまで名前が分からないクラスのインスタンスを作成します.
  • オブジェクトのメンバーを取得して設定する.このメンバーの名前はプログラムの実行中に知られている.
  • 実行中に名前を知るオブジェクトを検出する方法
  • 参考資料
  • java.lang.reflect
  • Java反射浅から深へ|進級必須
  • Java反射を深く解析(1)-ベース