JAva反射技術及びエージェントモード(二)


インスタンスInvokeTesterクラスのmain()メソッドでは,反射メカニズムを用いてInvokeTesterオブジェクトのadd()とecho()メソッドを呼び出す.
InvokeTester.java
import java.lang.reflect.Method;

public class InvokeTester
{
    public int add(int param1, int param2)
    {
        return param1 + param2;
    }

    public String echo(String msg)
    {
        return "echo: " + msg;
    }

    public static void main(String[] args) throws Exception
    {
        Class<?> classType = InvokeTester.class;
        Object invokeTester = classType.newInstance();

        // Object invokeTester = classType.getConstructor(new
        // Class[]{}).newInstance(new Object[]{});

        //   InvokeTester   add()  
        Method addMethod = classType.getMethod("add", new Class[] { int.class, int.class });
        Object result = addMethod.invoke(invokeTester, new Object[] { new Integer(100), new Integer(200) });
        System.out.println((Integer) result);

        //   InvokeTester   echo()  
        Method echoMethod = classType.getMethod("echo", new Class[] { String.class });
        result = echoMethod.invoke(invokeTester, new Object[] { "Hello" });
        System.out.println((String) result);
    }
}

add()メソッドの2つのパラメータはintタイプであり、add()メソッドを表すMethodオブジェクトを得るコードは以下の通りである.
Method addMethod=classType.getMethod("add",new Class[]{int.class,int.class});
Methodクラスのinvoke(Object obj,Object args[])メソッドが受信するパラメータはオブジェクトでなければなりません.パラメータが基本タイプデータの場合、対応するパッケージタイプのオブジェクトに変換する必要があります.invoke()メソッドの戻り値は常にオブジェクトであり、実際に呼び出されたメソッドの戻りタイプが基本タイプデータである場合、invoke()メソッドはそれを対応するパッケージタイプのオブジェクトに変換し、それを返します.
この例では、InvokeTesterクラスのadd()メソッドの両方のパラメータおよび戻り値がintタイプであるにもかかわらず、add Methodオブジェクトのinvoke()メソッドを呼び出すと、Integerタイプのパラメータのみが渡され、invoke()メソッドの戻りタイプもIntegerタイプであり、Integerクラスはint基本タイプのパッケージクラスである:
Object result=addMethod.invoke(invokeTester,
new Object[]{new Integer(100),new Integer(200)});
System.out.println((Integer)result); //result  Integer  

*************************************
java.lang.Arrayクラスは、配列要素を動的に作成およびアクセスするための様々な静的メソッドを提供します.ルーチン
ArrayTester 1クラスのmain()メソッドは、長さ10の文字列配列を作成し、インデックス位置5の要素を「hello」に設定し、インデックス位置5の要素の値を読み出す
ArrayTester1.java
import java.lang.reflect.Array;

public class ArrayTester1
{
    public static void main(String args[]) throws Exception
    {
        Class<?> classType = Class.forName("java.lang.String");
        //        10      
        Object array = Array.newInstance(classType, 10);
        //       5     "hello"
        Array.set(array, 5, "hello");
        //        5     
        String s = (String) Array.get(array, 5);
        System.out.println(s);
    }
}

インスタンスArrayTester 2クラスのmain()メソッドは、5 x 10 x 15の整数配列を作成し、インデックス位置が[3][5][10]の要素の値を37に設定します.
ArrayTester2.java
import java.lang.reflect.Array;

public class ArrayTester2
{
	public static void main(String args[])
	{
		//        
		int[] dims = new int[] { 5, 10, 15 };
		//    Array  ,    ,
		//Array.newInstance(Integer.TYPE, dims)        ,         
		Object array = Array.newInstance(Integer.TYPE, dims);
		//java     ,       ,        
		Object arrayObj = Array.get(array, 3);
		Class<?> cls = arrayObj.getClass().getComponentType();
		System.out.println(cls);
		//        
		arrayObj = Array.get(arrayObj, 5);
		//     10      
		Array.setInt(arrayObj, 10, 37);
		
		int arrayCast[][][] = (int[][][]) array;
		System.out.println(arrayCast[3][5][10]);
	}
}

******************************************************
“Class”   class
JavaにはObject classがあることはよく知られており、すべてのJava classesの継承の根源であり、すべてのJava classで書き換えるべきmethods:hashCode()、equals()、clone()、toString()、getClass()などが宣言されている.ここでgetClass()はClass objectを返します.
Class classは非常に特殊です.一般的なclassesと同様にObjectから継承され、Javaプログラムの実行時のclassesやinterfacesを表すために使用され、enum、array、primitive Java typesを表すためにも使用されます.
(boolean,byte,char,short,int,long,float,double)およびキーワードvoid.1つのclassがロードされるか、またはローダのdefineClass()がJVMによって呼び出されると、JVMは自動的に1つのClass objectを生成します.Java標準ライブラリのソースコードを変更してClass objectの実際の生成タイミングを観察したい場合(Classのconstructorにprintln()を追加するなど)、できません.Classはpublic constructorを持っていないので
ClassはReflectionの起源です.探査したいclassについては、まずClass objectを生成してから、後者を介して数十以上のReflection APIsを呼び出すことができます.
「Class」objectの取得方法
===========================================================
Class object誕生パイプ=例
===========================================================
getClass()の運用
注意:各classには、この関数=String str=「abc」があります.
                                          Class c1 = str.getClass();
===========================================================
Classを使うgetSuperclass()     =         Button b1 = new Button();
                                       Class c1 = b.getClass();
                                       Class c2 = c1.getSuperclass();
===========================================================
使用static method=Class c 1=Class.forName("java.String");
Class.forName()
(最もよく使われる)
&&&&&&&&&&&&&&&
ファイルをアップロードしましょう.
&&&&&&&&&&&&&&&
実行時にinstancesを生成
オブジェクトエンティティを生成するには、Reflectionダイナミックメカニズムに「引数なしctor」、「パラメータ付きctor」の2つの方法があります.「パラメータ付きctor」を呼び出すのが面倒な場合は、ClassのnewInstance()ではなく、ConstructorのnewInstance()を呼び出します.まず、Class[]をctorのパラメータタイプとして用意します(この例では指定します).
1つのdoubleとint)のために、getConstructor()を引数として呼び出し、固有のctorを取得します.次に、Object[]をctor実パラメータ値として準備し(この例では3.14159および125を指定)、上記の専属ctorのnewInstance()を呼び出します.
Class c = Class.forName("DynTest");
Object obj = null;
obj = c.newInstance();//     
System.out.println(obj);

「Class objectに対応するclass」のオブジェクトエンティティを動的に生成します.引数なし.
Class c = Class.forName("DynTest");
Class[] pTypes = new Class[]{double.class,int.class};
Constructor ctor = c.getConstructor(pTypes);
Object obj = null;
Object[] arg = new Object[]{3.124,23};
obj = ctor.newInstance(arg);
System.out.println(obj);

実行時にmethodsを呼び出す
この動作は、上記の呼び出し「パラメータ付きctor」とかなり似ています.まず、パラメータタイプとしてClass[]を用意し(この例では、1つがStringであり、もう1つがHashtableであることを指定します)、これを引数としてgetMethod()を呼び出し、特定のMethod objectを取得します.次に、Object[]を準備して引数を配置し、上記で得られた特定のMethod objectのinvoke()を呼び出します.
なぜMethod objectを取得するときに返信タイプを指定する必要がないのですか?
method overloadingメカニズムはsignatureが一意でなければならないことを要求するため、リターンタイプはsignatureの1つの成分ではない.すなわち,method名とパラメータ列を指定すれば,必ずユニークなmethodが指摘される.
Class c = Class.forName("java.lang.String");
Method method=c.getMethod(「method name」メソッドパラメータタイプ);
**************************
パラメータや引数が不要なため、以前の2つの動作に比べて「fieldコンテンツの変更」は簡単になりました.まずClassのgetField()を呼び出し、field名を指定します.特定のField objectを取得すると、Fieldのget()とset()を直接呼び出すことができます.
import java.lang.reflect.Field;

public class Test {
	public double d;
	public static void main(String[] args) throws Exception {
		Class<?> c = Class.forName("Test");
		//         Field  
		Field f = c.getField("d");
		Test obj = new Test();
		//  Field  get            
		System.out.println("d= "+(Double)f.get(obj));
		f.set(obj, 12.36);
		System.out.println("d= "+obj.d);
	}
}