JAva反射単純記録

8248 ワード

まず簡単な例で反射の使用を見てみましょう.まずテストクラスを定義します.
package com.example.myapplication;
public class TestClass {

    public  void hi(int age,String name){
        System.out.println("    ,  " + name+",   " + age+" ");
    }
}

そしてactivityで呼び出す
        Class testClass = null;
        Method method = null;
        try {
            testClass = Class.forName("com.example.myapplication.TestClass");
            method = testClass.getDeclaredMethod("hi",new Class[]{int.class,String.class});
            method.invoke(testClass.newInstance(),20,"abc");
        } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException | ClassNotFoundException e) {
            e.printStackTrace();
        }

最後の出力
I/System.out:     ,  abc,   20 

つまり、Classからmethod(メソッド名)を取得した後、methodを呼び出す.invoke、これらはTestClassオブジェクトを新規作成し、そのオブジェクトのmethodを呼び出すことに相当します.以前は反射に有用だったのは,webviewがシステム署名を付けて崩壊したためであり,この文章に基づいて解決策を見つけたが,反射についてはあまり知られていない.多くの場合、一つのものを使うが、実際にはその背後の原理を理解していない.【作業概要】システム署名アプリがwebview(Android 5.0+)フラッシュバックを実行する問題Androidソースコードの多くは、取得も修正もできない、例えば上記の例のWebViewFactoryですが、目的を達成するためにWebViewFactoryを修正せざるを得ない場合があります.そうしないとプログラムが正常に動作しない場合があります.この場合javaの反射が役に立ちます.
では、この原理は何ですか.まず、Javaプログラミングのダイナミック性という一連の文章を見て、ソースコードから実行プログラムまでの多くの背後の詳細を検討しました.一度通読することをお勧めします.ここにはいくつかのキーワードがあります:バイナリで表されるクラス、クラスを読み込みバイナリで表されるクラスコンパイラはjava言語を書きます.JAvaファイルをコンパイルし、バイナリクラス(バイナリクラスフォーマットは実際にはJVM仕様で定義)を生成し、拡張子に格納する.classのファイルにあります..classは実行中のJVMにロードされます.
出典:Javaプログラミングの動的読み込みクラス:CやC++などのコストマシンコードをコンパイルする言語は、通常、ソースコードをコンパイルした後にこのステップをリンクする必要があります.このリンク・プロシージャは、独立してコンパイルされた各ソース・ファイルからのコードと共有ライブラリ・コードを統合し、実行可能なプログラムを形成します.Java言語を使用すると、コンパイラによって生成されたクラスは、JVMにロードされる前に通常元のままになります.クラスの読み込みと初期化において、JVM内部では、バイナリクラスのフォーマットの復号化、他のクラスとの互換性の確認、バイトコードの操作の順序の検証、javaの最終的な構築など、多くの操作が完了する.lang.Classインスタンスは、新しいクラスを表します.このClassオブジェクトは、JVMが新しいクラスを作成するすべてのインスタンスの基礎となります.JVMに読み込まれた同じバイナリクラスについては、複数のコピーがあり、各コピーには独自のClassインスタンスがあります.これらのレプリカは同じクラス名を共有していても、JVMには独立したクラスです.ここにクラスを入れるのは違和感があるように見えますが、最初は名詞なのか動作なのか分かりません.「クラスを読み込む」か「クラスを読み込む」か、後で考えると、classはJVMを読み込みます.
クラスとクラスの読み込みを見てから反射を見ると、反射を理解するのに役立ちます.ひきこみはんしゃ
出典:反射を導入反射を使用する従来のJavaプログラミングとは異なり、メタデータ--他のデータを記述するデータと連携しています.Java言語反射アクセスの特殊なタイプの元データは、JVMにおけるクラスとオブジェクトの記述である.反射により、実行時に広範なクラス情報にアクセスできます.フィールドを読み書きし、実行時に選択したクラスのメソッドを呼び出すこともできます.まずclassを取得します.
Class clas = MyClass.class;

これはMyClassです.JAvaは自分で定義した場合の書き方です.実行時に特定の外部ソースからクラス名を読み込む必要がある場合、つまりAndroidソースコードのクラス名と同様です.クラス・インストーラを使用してクラス情報を検索する必要があります.次の方法を説明します.
// "name" is the class name to load
Class clas = null;
try {
  clas = Class.forName(name);
} catch (ClassNotFoundException ex) {
  // handle exception case
}
// use the loaded class

クラスがすでに読み込まれている場合は、既存のClass情報が得られます.クラスが読み込まれていない場合、クラス・ローダは現在読み込まれ、新しく作成されたクラス・インスタンスに戻ります.ClassについてforName()はこの編を見ることができます:Class.forName()の役割と使用の概要
バイナリフォーマットを取得しました.classクラスの後、次はクラスベースの反射です.
クラス内のコンストラクション関数、フィールド、メソッドについてjava.lang.Classは4つの独立した反射呼び出しを提供し、異なる方法で情報を得る.1.コンストラクション関数の反射は、まず、コンストラクション関数の反射呼び出しを見る.Constructorの意味は構造者です.
Constructor getConstructor(Class[] params) 
Constructor[] getConstructors()  
Constructor getDeclaredConstructor(Class[] params) 
Constructor[] getDeclaredConstructors() 

ここではConstructorまたはConstructor[]を返します.では、どのように使いますか.ここでは、getConstructorの使用を一例で説明します.
public class TwoString {
    private String m_s1, m_s2;
    public TwoString(String s1, String s2) {
        m_s1 = s1;
        m_s2 = s2;
        System.out.println("m_s1 = " + m_s1 + " , m_s2 = " +m_s2);
    }
}

次に、コンストラクション関数の反射呼び出しです.Constructor.newInstanceはTwoStringを呼び出す構造関数に相当する.
Class[] types = new Class[] { String.class, String.class };
Constructor cons = TwoString.class.getConstructor(types);
Object[] args = new Object[] { "a", "b" };
TwoString ts = cons.newInstance(args);

Android studioで実際に実行する場合は少し修正しますが、上のコードにtry catch異常が付いていないのでエラーメッセージが表示されますので、プロンプトに従って自動的に補完すればいいです.
        Class[] types = new Class[] { String.class, String.class };
        Constructor cons = null;
        try {
            cons = TwoString.class.getConstructor(types);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        Object[] args = new Object[] { "a", "b" };
        try {
            TwoString ts = (TwoString) cons.newInstance(args);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

最終運転出力I/System.out: m_s1 = a , m_s2 = b.すなわち,上記のコードは,構造関数の呼び出し,すなわちクラスの新規作成を完了した.2.フィールドの反射は、フィールドの反射を見てみましょう.Classでも4つの方法が提供されています.
Field getField(String name)  
Field[] getFields()  
Field getDeclaredField(String name)  
Field[] getDeclaredFields()  

次の例は、intタイプを新しく追加したフィールドに値を割り当てることです.まず、TwoStringにcountを追加します.
public class TwoString {
    private String m_s1, m_s2;
    public int count;
     public TwoString(String s1, String s2) {
        m_s1 = s1;
        m_s2 = s2;
    }
}

次に、関数を追加します.
    public int incrementField(String name, Object obj) throws NoSuchFieldException, IllegalAccessException {
        Field field = obj.getClass().getDeclaredField(name);
        int value = field.getInt(obj) + 1;
        field.setInt(obj, value);
        return value;
    }

最後の呼び出し
        TwoString mTwoString = new TwoString("a","b");
        try {
            incrementField("count",mTwoString);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        Log.d(TAG,"count = " + mTwoString.count);

出力logは以下の通りです.
D/MainActivity: count = 1

3.方法の反射は依然として4つの方法を提供している.
Method getMethod(String name, Class[] params)  
Method[] getMethods()  
Method getDeclaredMethod(String name, Class[] params)  
Method[] getDeclaredMethods()  

例を見てみましょう.
   public int incrementProperty(String name, Object obj) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
       String prop = Character.toUpperCase(name.charAt(0)) +
               name.substring(1);
       String mname = "get" + prop;
       Class[] types = new Class[] {};
       Method method = obj.getClass().getMethod(mname, types);
       Object result = method.invoke(obj, new Object[0]);
       int value = ((Integer)result).intValue() + 1;
       mname = "set" + prop;
       types = new Class[] { int.class };
       method = obj.getClass().getMethod(mname, types);
       method.invoke(obj, new Object[] { new Integer(value) });
       return value;
   }

JavaBeanを定義します.
public class JavaBean {
    private int count;

    public int getCount(){
        return count;
    }

    public void setCount(int count){
        this.count = count;
    }
}

最後の呼び出し
       JavaBean javaBean = new JavaBean();
        try {
            incrementProperty("count",javaBean);
         }  catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        Log.d(TAG,"count = " + javaBean.getCount());

出力logは以下の通りです.
D/MainActivity: count = 1

デフォルトの初期化値は0、+1後は1なのでjavaBeanのcountの最後の値は1です.上のコードはgetCountとsetCountを呼び出す呼び出しを示しています.
以上が構造関数,フィールド,メソッドの反射である.反射については、ここまでです.もっと多くの使い方がありますが、ここでは詳しく説明しません.
参照リンク:クラスとクラスは、反射とXMLを組み合わせてJavaプログラミングを実現するダイナミッククラスを導入する.forName()の役割と使用概要【作業概要】システム署名app実行webview(Android 5.0+)フラッシュバック問題Android Hook技術と簡単な実戦を理解する