Javaベースの反射メカニズムの詳細

9186 ワード

いちばん前に書く
前の段落の文章がみんなに助けをもたらすことができて、みんながすべて基础知识がプログラマーにとって问题を解决する基础であることを知っていることを信じて、笔者のシリーズの文章は英语の定义、考え方の分析、実例の応用から一歩一歩重要な基础知识に対して说明して、関心のない子供靴は急いで関心を持って、笔者と一绪にあなた达の基础を固めましょう!
前文の住所を添付します:10個の無視できないJavaの基礎知識
前回の記事ではJavaの反射メカニズムについて言及したが,説明が透徹していないという読者のプライベートな反応があり,依然として愚かな状態であるため,本稿では詳細に説明する.
RTTIと反射?
これはよく混同される問題だ.RTTI or Reflection? 「Thinking in Java」を見たことがあると信じている学生は、Type Informationの章にこのような言葉がある.
Java allows you to discover information about objects and classes at run time. This takes two forms: "traditional"RTTI, which assumes that you have all the types available at compile time, and the reflection mechanism, which allows you to discover and use class information solely at run time.
その中でRTTI(Runtime Type Information)はC++の一つの概念であり、B大が明らかに先学したC++であり、この本の前にも『Thinking in C++』を出版したことがあるので、この名詞に深い感情を持っているのかもしれない.要するに、RTTIと反射(Reflection)の違いを区別しようとしないでください.この2つは老人と男のように、分けて理解するのは愚かです.
ここでは、TIJのような神書も、一人一人が知識を理解するのに適しているわけではありません.一部の紙面では、自分が詰まっていることに気づいたら、必ず例をたくさん見て、資料をたくさん調べて、自分が悟った道理で説明して、死の定義に絡まないでください.
反射の目的
多くの人が本稿で述べた内容を熟練した後もRTTIの目的を理解していないのは、一般的に2つの原因がある.1つはコードの作成量が小さすぎて、自分の設計の経験が不足していること、2つは動的な設計構想を備えていないことである.まず、次の例(TIJから)を見てみましょう.
import java.util.*;

abstract class Shape{
    void draw() {
        System.out.println(this + ".draw() ");
    }
    abstract public String toString();
}

class Circle extends Shape {
    public String toString() {
        return "Circle ";
    }
}

class Square extends Shape {
    public String toString() {
        return "Square ";
    }
}

class Triangle extends Shape {
    public String toString() {
        return "Triangle ";
    }
}

public class Shapes {
    public static void main(String[] args) {
        List shapeList = Arrays.asList(
            new Circle(), new Square(), new Triangle()
            );
        for (Shape shape : shapeList) {
            shape.draw();
        }
    }
}

前の例では、Circle、Triangle、Squareの3つのサブクラスであるShapeクラスを作成しました.メインメソッドではShapeのlistを作成し,匿名で3種の参照を作成したが,ここでは強制的にShapeに変換されていることが分かる.出力値は次のとおりです.
/* 
Output:
Circle.draw()
Square.draw()
Triangle.draw()
*/

このことから,多状態(Polymorphism),すなわちサブクラスでtoString()を書き換える方法を熟知することによって,実行中にタイプ情報を取得する最も基礎的な方法を実現した.この方法により、コードの読み書きやメンテナンスが容易になり、設計も理解されやすくなり、実行されたり、修正されたりすることができます.しかし、draw()メソッドが実行されるだけでなく、rotate()などのすべてのサブクラスに適用されないメソッドを実行する必要があります.回転はCircleにとって実行に意味がありません.反射メカニズムが必要です.Shapeを他のサブクラスに属する独自のメソッドに呼び出すことができます.
ここでは定義だけで説明するのは確かに難しいので、通俗的な例を挙げましょう.例えばスクリーンにはいろいろな果物、りんご、梨、バナナがたくさんあります.りんごがクリックされると爆発方法、バナナがクリックされると皮むき方法、梨がクリックされると半分に切ります.では、ユーザーがどの果物をクリックしているのか分かりませんが、この果物の方法を直接実行したいと思っています.このとき、反射メカニズムを利用すると、私たちのコードが簡単に読め、再開発を修正するのに役立ちます.
Classタイプおよびオブジェクトの取得方法
ランタイム(runtime)にタイプ情報を格納するClassオブジェクト、プログラム内の任意のクラス、コンパイル時にこのClassオブジェクトが作成されます.簡単に言えば、コンパイル後に現れたName.classというファイルです.Nameはあなたのクラス名と同じ名前です(このオブジェクトを作成したのはJVMのサブシステムで「class loader」と呼ばれています).JavaでClassタイプを取得する方法は、次の3つです.
  • .class

  • すべての参照データ型はクラス名に「.class」を付けてClass型を取得できます.この方法は静的です.ここで、基本的なタイプであれば、「int.class」に対応する「Integer.TYPE」のような「パッケージクラス.TYPE」の方法も使用できます.
  • Class.forName()

  • クラスのString名によってClassタイプを取得します.この方法は前述のように静的であり、ClassNotFoundExceptionを放出する必要があります.
  • getClass()

  • この方法はインスタンス名でClassタイプを取得するのが動的である点は前の2つとは異なり区別に注意する.
    上記の3つの方法を総合的に見ると、1つの表で簡単に区別します.
    メソッド名
    取得形式
    .class
    宣言時のクラスの取得
    getClass()
    実行時のクラスの取得
    Class.forName()
    クラス名によるクラスの取得
    タイプを取得した後、newInstance()メソッドを追加すると、次のようなオブジェクトを作成できます.
    Class cc = Class.forName("Daniel");
    
    Object oo = cc.newInstance();
    //        cc        
    

    クラス内のプロパティの取得方法
    Classオブジェクトがあれば、もちろんそのメソッドとパラメータを実行または変更したいと思います.ここで最も一般的なのはgetDeclaredFields()メソッドです.例:
    Class cc = Class.forName("Daniel");
    
    Field[] field = cc.getDeclaredFields();  
    

    クラスには多くの方法があるので、Field配列を定義する必要があります.ここでよく使われる方法は以下の表に列挙しますが、必要に応じて特定の方法を組み合わせるだけで、理解しやすいです.
    方法
    さぎょう
    getDeclaredMethods()
    すべてのメソッドを取得
    getReturnType()
    取得メソッドの戻りタイプ
    getParameterTypes()
    メソッドの入力パラメータタイプを取得
    getDeclaredMethod("",.class,……)
    特定のメソッドを取得
    getDeclaredConstructors()
    すべての構築方法を取得
    getDeclaredConstructor(.class,……)
    特定の構築方法の取得
    getSuperclass()
    クラスの親を取得
    getInterfaces()
    実装されたインタフェースの取得
    以上の方法で逆コンパイルを行い,我々のコードをより柔軟にすることもOOタイププログラミングの究極の目標である.
    ここでは、前回のCSDNの例を見てみましょう.
    import java.lang.reflect.Array;     
    import java.lang.reflect.Constructor;     
    import java.lang.reflect.Field;     
    import java.lang.reflect.Method;     
        
        
    /**   
     * JavaReflection Cookbook   
     *   
     * @author Michael Lee   
     * @since 2006-8-23   
     * @version 0.1a   
     */    
        
    public class Reflection {     
        /**   
         *               
         *   
         * @param owner, fieldName   
         * @return         
         * @throws Exception   
         *   
         */    
        public Object getProperty(Object owner, String fieldName) throws Exception {     
            Class ownerClass = owner.getClass();     
        
            Field field = ownerClass.getField(fieldName);     
        
            Object property = field.get(owner);     
        
            return property;     
        }     
        
        /**   
         *               
         *   
         * @param className        
         * @param fieldName         
         * @return         
         * @throws Exception   
         */    
        public Object getStaticProperty(String className, String fieldName)     
                throws Exception {     
            Class ownerClass = Class.forName(className);     
        
            Field field = ownerClass.getField(fieldName);     
        
            Object property = field.get(ownerClass);     
        
            return property;     
        }     
        
        
        /**   
         *           
         *   
         * @param owner   
         *                 
         * @param methodName   
         *                  
         * @param args   
         *                 
         * @return         
         * @throws Exception   
         */    
        public Object invokeMethod(Object owner, String methodName, Object[] args)     
                throws Exception {     
        
            Class ownerClass = owner.getClass();     
        
            Class[] argsClass = new Class[args.length];     
        
            for (int i = 0, j = args.length; i < j; i++) {     
                argsClass[i] = args[i].getClass();     
            }     
        
            Method method = ownerClass.getMethod(methodName, argsClass);     
        
            return method.invoke(owner, args);     
        }     
        
        
          /**   
         *             
         *   
         * @param className   
         *                 
         * @param methodName   
         *                  
         * @param args   
         *                   
         * @return             
         * @throws Exception   
         */    
        public Object invokeStaticMethod(String className, String methodName,     
                Object[] args) throws Exception {     
            Class ownerClass = Class.forName(className);     
        
            Class[] argsClass = new Class[args.length];     
        
            for (int i = 0, j = args.length; i < j; i++) {     
                argsClass[i] = args[i].getClass();     
            }     
        
            Method method = ownerClass.getMethod(methodName, argsClass);     
        
            return method.invoke(null, args);     
        }     
        
        
        
        /**   
         *        
         *   
         * @param className   
         *                 
         * @param args   
         *                      
         * @return         
         * @throws Exception   
         */    
        public Object newInstance(String className, Object[] args) throws Exception {     
            Class newoneClass = Class.forName(className);     
        
            Class[] argsClass = new Class[args.length];     
        
            for (int i = 0, j = args.length; i < j; i++) {     
                argsClass[i] = args[i].getClass();     
            }     
        
            Constructor cons = newoneClass.getConstructor(argsClass);     
        
            return cons.newInstance(args);     
        
        }     
        
        
             
        /**   
         *             
         * @param obj      
         * @param cls     
         * @return    obj       ,    true   
         */    
        public boolean isInstance(Object obj, Class cls) {     
            return cls.isInstance(obj);     
        }     
             
        /**   
         *              
         * @param array      
         * @param index      
         * @return                   
         */    
        public Object getByArray(Object array, int index) {     
            return Array.get(array,index);     
        }     
    }
    

    もう一度見ると、以上は様々な方法の応用を簡単に書くだけで、あまり論理的ではないことがわかります.簡単に言えば、このタイプのコードは私たちにとって辞書型の材料にすぎず、設計の過程ですぐに調べて使うので、一つ一つ暗記する必要はありません.
    締めくくり
    Java反射部分の知識については,本稿でもあまり差がない.反射メカニズムについては、文法を理解するよりも、設計モードでの役割を理解することが重要ですが、設計モードはJavaプログラミング思想の中でかなり重要な一環であり、関連内容は後続の文章でも言及される可能性がありますので、引き続き注目してください.
    文章の中で間違いや気に入らないところがあれば、私信作者の微博:LightningDCまたは直接文章の下で返事して交流することを歓迎します.筆者はまた引き続きみんなのために更新して、関心を歓迎して、もし文章があなたに役に立つならば、手当たり次第にいいねをつけましょうははは、コードワードは容易ではありません.