[ジャワ] Javaリフレクションの-depth分析(1) - 基本

記事タイトル:洞察Javaリフレクション(1) -基本的な
記事の著者:sczyh30
元のリンク:http://www.sczyh30.com/posts/Java/java-reflection-1/
ライセンス:元のリンクと著者を保持してください再現

*本論文では、JDK 1.8に基づいて基本的な記事です。

I.レビュー:反射とは何ですか?

リフレクション(反射)は、Javaの特徴の一つである、それはJavaプログラムは、取得した独自の情報で実行すると、クラスやオブジェクトの内部属性を操作することができることができます。

Oracleの反射のための公式の説明:

リフレクションは、ロードされたクラスのフィールド、メソッドおよびコンストラクタに関する情報を検出するためのJavaコードを可能にし、セキュリティ上の制限の範囲内で、その基礎となる対応部分を操作することフィールド、メソッド、およびコンストラクタを使用します。
APIは、(実行時のクラスに基づく)ターゲットオブジェクトのパブリックメンバーまたは指定されたクラスが宣言したメンバーのいずれかへのアクセスを必要とするアプリケーションに対応します。また、プログラムはデフォルトのリフレクションアクセス制御を抑止することができます。

要するに、反射によって、我々は、実行時にすべてのタイプのプログラムまたはアセンブリのメンバーとメンバーについての情報を得ることができます。オブジェクトの一般的なタイプのプログラムをダウンコンパイル時に決定され、Javaリフレクションを動的にオブジェクトを作成し、そのプロパティを呼び出すために、オブジェクトのこのタイプは、コンパイル時に知られていません。だから我々は、オブジェクトの型がコンパイル時に知られていない場合でも、直接反射機構によってオブジェクトを作成することができます。

コアは、それは(コードを書いたりコンパイル)事前にオブジェクトを実行するか分からない必要があり、実行時に動的クラスやメソッドのコール/アクセスプロパティにロードされたJVMを反映しているそう。

Javaのリフレクションは、以下の機能を提供します。

  • ランタイムオブジェクトで決定することは、どのクラスに属します。
  • 任意の構成内のオブジェクトのランタイムクラスでは、
  • 任意のクラスを分析して、実行時にメンバ変数とメソッド(あるいは反射法により、プライベートと呼ぶことができる)を有しています。
  • 実行時にオブジェクトのメソッドのいずれかを呼び出します

重要:ランタイムは、コンパイルではなく、ある場合には

反射の第二に、主な目的

多くの人々が広くJavaアプリケーションの実際の開発に反映されていないと思い、そうではありません。我々はポイント数に応じて、我々はオブジェクトまたはクラスを入力し、それをプロパティやメソッドを呼び出したい、(などのEclipse、IDEAなど)IDEを使用すると、コンパイラが自動的にここでは、そのプロパティやメソッドに記載されているだろうこれは、リフレクションを使用します。
最も重要な使用を反映して、共通のフレームワークの様々な開発です。
多くのフレームワーク(Springなど)、ユニバーサルフレームワークを確保するために、彼らは私たちは、この時間を使用する必要があり、別のメソッドを呼び出し、プロファイルに基づいて、異なるオブジェクトまたはクラスをロードする必要があるかもしれません(たとえば、XML設定ファイルビーンを介するなど)の設定があります反射オブジェクトは、実行時に動的にロードされるロードする必要があります。

例として、我々は一般的にアクションで構成された開発のStrutsの2フレームワークの使用に行くstruts.xml、例えば:

<action name="login"
        class="org.ScZyhSoft.test.action.SimpleLoginAction"
        method="execute">
    <result>/shop/shop-index.jsp</result>
    <result name="error">login.jsp</result>
</action>

プロファイルおよびアクションマッピング関係を確立し、表示層が要求を出したときに、要求が続いStrutsPrepareAndExecuteFilterアクションインスタンスに行きます、StrutsPrepareAndExecuteFilterをブロックされますが、動的に作成されます。たとえば、私たちはlogin.actionを要求し、その後、StrutsPrepareAndExecuteFilterはアクションでのログイン名のstruts.xmlファイル検索行動を解決するために行く、およびプロパティSimpleLoginActionインスタンスに基づいてクラスを作成し、executeメソッドを呼び出すメソッドを呼び出します、このプロセスは、反射せずに行うことはできません。

そして、開発者のためのフレームワークは、小さいが非常に大きな役割を反映して、それが実装された容器の様々なコアです。一般的な開発者のために、少しの反射と枠組みのない綿密な開発は少しになりますが、根本的な制度的枠組みを見て自分のプログラミングのアイデアを豊かにするのに役立ちます、非常に便利です。

第三に、反射の基本的な使用

我々は分析のクラスに属し、上述した任意のオブジェクトの反射のために使用することができる、クラスオブジェクトを取得し、オブジェクトは、任意の呼び出しオブジェクトを構築します。ここでは、基本的な反射機能を使用すると実装(関連するクラスは、一般的にjava.lang.relfect袋に反映されている)を導入します。

1、Classオブジェクト

3つの方法があります。

  1. ForNameはClassクラスの静的メソッドを使用します。
public static Class<?> forName(String className)
/**
 *	比如在 JDBC 开发中常用此方法加载数据库驱动:
 *	Class.forName(driver);
 **/
  1. 次のようなオブジェクトの特定のクラスへの直接アクセス、
Class<?> klass = int.class;
Class<?> classInt = Integer.TYPE;
  1. 例えば、オブジェクトのgetClass()メソッドを呼び出します。
StringBuilder str = new StringBuilder("123");
Class<?> klass = str.getClass();

図2に示すように、それはクラスのインスタンスかどうかが判定されます

一般的に、我々は、クラスのインスタンスかどうかを判断するためには、instanceofキーワードを使用します。我々はまた、ネイティブメソッドであるクラスのインスタンスかどうかを決定するためにクラスでisinstance()メソッド内のオブジェクトによって反射することができます。

public native boolean isInstance(Object obj);

図3に示すように、インスタンスを作成します

それは、2つの方法で主にオブジェクトを反射することによって生成されます。

  1. newInstance()メソッドを使用して、クラスオブジェクトは、対応するクラスのクラスのオブジェクトのインスタンスを作成します。
Class<?> c = String.class;
Object str = c.newInstance();
  1. 最初のオブジェクトで指定されたクラスコンストラクタオブジェクトを取得し、インスタンスを作成するためのコンストラクタオブジェクトのnewInstance()メソッドを呼び出します。このメソッドは、クラスのコンストラクタの特定のインスタンスで構成することができます。
//获取String所对应的Class对象
Class<?> c = String.class;
//获取String类带一个String参数的构造器
Constructor constructor = c.getConstructor(String.class);
//根据构造器创建实例
Object obj = constructor.newInstance("23333");
System.out.println(obj);

図4に示すように、取得方法

Classオブジェクトは、主に以下の方法で、メソッドのセットを取得します:

  1. すべてのメソッドのgetDeclaredMethods方法は、公開、保護され、デフォルト(パッケージ)アクセス、およびprivateメソッドを含むクラスまたはインタフェースの宣言を、返しますが、除外メソッドを継承しています。
public Method[] getDeclaredMethods() throws SecurityException
  1. getMethods方法は、そのパブリックメソッド継承クラスを含むクラスのすべてのパブリック(パブリック)メソッドを返します。
public Method[] getMethods() throws SecurityException
  1. getMethodメソッドは最初のパラメータは、メソッドの名前である特定の方法を返し、後者のパラメータは、クラスのメソッドのパラメータに対応するオブジェクトです。
public Method getMethod(String name, Class<?>... parameterTypes)

ただ、そう説明し、私たちがこれらの3つのメソッドを理解するために例を使用し、理解することは難しいかもしれません。

package org.ScZyhSoft.common;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class test1 {
	public static void test() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
	        Class<?> c = methodClass.class;
	        Object object = c.newInstance();
	        Method[] methods = c.getMethods();
	        Method[] declaredMethods = c.getDeclaredMethods();
	        //获取methodClass类的add方法
	        Method method = c.getMethod("add", int.class, int.class);
	        //getMethods()方法获取的所有方法
	        System.out.println("getMethods获取的方法:");
	        for(Method m:methods)
	            System.out.println(m);
	        //getDeclaredMethods()方法获取的所有方法
	        System.out.println("getDeclaredMethods获取的方法:");
	        for(Method m:declaredMethods)
	            System.out.println(m);
	    }
    }
class methodClass {
    public final int fuck = 3;
    public int add(int a,int b) {
        return a+b;
    }
    public int sub(int a,int b) {
        return a+b;
    }
}

次のように実行されるプログラムの結果:

getMethods获取的方法:
public int org.ScZyhSoft.common.methodClass.add(int,int)
public int org.ScZyhSoft.common.methodClass.sub(int,int)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
getDeclaredMethods获取的方法:
public int org.ScZyhSoft.common.methodClass.add(int,int)
public int org.ScZyhSoft.common.methodClass.sub(int,int)

この方法は、このようなjava.lang.Objectの定義された種々の方法として親クラスの取得getMethods()メソッドで取得することができ、見ることができます。

情報を取得するように構成された5、

上記と同様の使用状況や使用状況を取得するためのクラスのコンストラクタメソッドを取得します。そして、クラスコンストラクタgetConstructorメソッドClassクラスのインスタンスによって取得され、クラスコンストラクタnewInstanceメソッドは、オブジェクトのインスタンスを作成することができます。

public T newInstance(Object ... initargs)

このメソッドは、オブジェクトのインスタンスを作成するためのコンストラクタを通過した対応するパラメータに応じて呼び出すことができます。

6、メンバ変数(フィールド)のクラスを取得するための情報

主にこれらの方法はここでは繰り返しません。

  • getFiled:パブリックメンバ変数へのアクセス
  • getDeclaredField:すべてのメンバ変数が宣言されているが、親クラスのメンバ変数にはできません

getFileds getDeclaredFields方法および上記のように使用する(方法を参照)。

7、メソッドを呼び出します

私たちはクラスから方法を取得する場合、我々は、このメソッドを呼び出すために()メソッドを呼び出します。プロトタイプinvokeメソッドは次のとおりです。

public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException

次に例を示します。

public class test1 {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class<?> klass = methodClass.class;
        //创建methodClass的实例
        Object obj = klass.newInstance();
        //获取methodClass类的add方法
        Method method = klass.getMethod("add",int.class,int.class);
        //调用method对应的方法 => add(1,4)
        Object result = method.invoke(obj,1,4);
        System.out.println(result);
    }
}
class methodClass {
    public final int fuck = 3;
    public int add(int a,int b) {
        return a+b;
    }
    public int sub(int a,int b) {
        return a+b;
    }
}

私は詳細な分析専用の記事を書きます背面の詳細な呼び出し方法は、プロセスを呼び出します。ジャンプするにはこちらをクリック

図8に示すように、アレイを作成するためにリフレクションを使用して

アレイは、オブジェクト参照に割り当てることができ、Javaで特殊なタイプです。アレイを作成するためにリフレクションを使用した例を見てみましょう:

public static void testArray() throws ClassNotFoundException {
        Class<?> cls = Class.forName("java.lang.String");
        Object array = Array.newInstance(cls,25);
        //往数组里添加内容
        Array.set(array,0,"hello");
        Array.set(array,1,"Java");
        Array.set(array,2,"fuck");
        Array.set(array,3,"Scala");
        Array.set(array,4,"Clojure");
        //获取某一项的内容
        System.out.println(Array.get(array,3));
    }

前記java.lang.reflect.ArrayのArrayクラスカテゴリ。我々は()Array.newInstanceによるオブジェクトの配列を作成するには、そのプロトタイプは次のようになります。

public static Object newInstance(Class<?> componentType, int length)
        throws NegativeArraySizeException {
        return newArray(componentType, length);
    }

NEWARRAY方法は、HotSpotのJVMの実装では、特に私たちの後ろで、その後、ソースコードは最初ここに掲載勉強ネイティブメソッド、次のとおりです。

private static native Object newArray(Class<?> componentType, int length)
        throws NegativeArraySizeException;

ソースディレクトリ:OpenJDKの\ホットスポット\のsrc \共有\ VMの\ランタイムの\ reflection.cpp

arrayOop Reflection::reflect_new_array(oop element_mirror, jint length, TRAPS) {
  if (element_mirror == NULL) {
    THROW_0(vmSymbols::java_lang_NullPointerException());
  }
  if (length < 0) {
    THROW_0(vmSymbols::java_lang_NegativeArraySizeException());
  }
  if (java_lang_Class::is_primitive(element_mirror)) {
    Klass* tak = basic_type_mirror_to_arrayklass(element_mirror, CHECK_NULL);
    return TypeArrayKlass::cast(tak)->allocate(length, THREAD);
  } else {
    Klass* k = java_lang_Class::as_Klass(element_mirror);
    if (k->oop_is_array() && ArrayKlass::cast(k)->dimension() >= MAX_DIM) {
      THROW_0(vmSymbols::java_lang_IllegalArgumentException());
    }
    return oopFactory::new_objArray(k, length, THREAD);
  }

さらに、Arrayクラスのセットと方法はHotSpotのJVMが解決ここでは詳細に説明されていない、リフレクション:: array_setリフレクション:: array_getとメソッドに対応ネイティブメソッド、あります。

第四に、検討事項のいくつかの反射

反射するので、余分ないくつかのシステムリソースを消費するので、あなたが動的にオブジェクトを作成する必要がない場合は、反射を必要としません。

また、あなたは、メソッドを呼び出すための権限反射を確認する際に無視することができますので、カプセル化を弱体化し、セキュリティ上の問題につながる可能性があります。

おすすめ

転載: blog.csdn.net/shaotaiban1097/article/details/91947788