Method.invoke - Javaメソッドの動的に実行

2009/02/13 11:59Update
TAGS: Method.invoke | メソッド | リフレクション

Javaリフレクション機能を利用して、Javaメソッドを動的に実行させるサンプルです。

Javaでは、クラスとオブジェクトに関するリフレクト情報を取得するAPIを提供します。
これらのリフレクションAPIはjava.lang.reflectパッケージにまとめて提供されています。

Javaリフレクションの使用シーン


◇ 設定ファイルから指定するクラスやメソッドを実行する必要がある場合。たとえば、HibernateなどのORMツールは、設定ファイルに書かれたJDBCドライバークラスを変えるだけで、違うデータベースに接続させる仕組みはリフレクションを利用しています。
◇ フレームワークや外部ツールなど。SpringやJSF、Strutsなどのフレームワークは、動的にインスタンスの生成やメソッドの呼び出しがあります。これらのフレームワークもJavaリフレクション機能を利用しています。

動的にクラスに実行について、次の記事をご参照ください。
Class.forName/newInstance - 文字列からインスタンスを生成

本文は、Javaメソッドを動的に実行させる方法および実装手順について学びます。

関連するリフレクト情報を取得するクラスおよびインタフェース
java.lang.reflect.Method
java.lang.reflect.Field

サンプル


シンプルなサンプルから説明します。

Javaコード:
package com.test.reflection;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * リフレクション・サンプル
 * 1)指定するフィールド名のフィールド値を取得
 * 2)指定するフィールド名のフィールド値を設定
 * 3)動的にMethodを実行(Method.invoke)
 *
 */
public class TestReflection {
    public static void main(String []args) {
        
        try {
            MyClass obj = new MyClass("Hello", 20);
            
            System.out.println("****************フィールド値取得*****************");
            String userName = (String)getFieldValueByName(obj, "userName");
            int age = (Integer)getFieldValueByName(obj, "age");
            
            System.out.println(userName);
            System.out.println(age);
            
            System.out.println("****************フィールド値設定*****************");
            setFieldValueByName(obj, "userName", "新しい名だよ");
            setFieldValueByName(obj, "age", 30);
            
            System.out.println(obj.getUserName());
            System.out.println(obj.getAge());
        } catch (Exception e) {    //by Class.forName
            e.printStackTrace();
        }
    }
        
    /**
     * オブジェクトのフィールド値を取得する
     * @param object    取得する対象となるオブジェクト    
     * @param fieldName フィールド名
     * 
     */
    public static Object getFieldValueByName( 
            Object object, String fieldName) 
    throws SecurityException, NoSuchMethodException, 
    IllegalArgumentException, IllegalAccessException, InvocationTargetException {
        
        if (object == null)
            return null;
        
        Class cls = object.getClass();

        //フィールドのgetメソッド名を取得
        char firstChar = fieldName.charAt(0);
        char uFirstChar = Character.toUpperCase(firstChar);
        String getMethod = "get"
                + fieldName.replaceFirst(String.valueOf(firstChar),
                        String.valueOf(uFirstChar));
        
        //getメソッドを取得
        Method method = cls.getMethod(getMethod, null);
        //getメソッドを呼び出し、戻り値はフィールドの値になります
        Object objValue = method.invoke(object, null);
        
        return objValue;
    }
    
    /**
     * オブジェクトのフィールド値を設定する
     * @param object    対象となるオブジェクト    
     * @param fieldName フィールド名
     * 
     */
    public static void setFieldValueByName(
            Object object,
            String fieldName, 
            Object fieldValue) 
    throws SecurityException, NoSuchFieldException, IllegalArgumentException, 
    IllegalAccessException, InvocationTargetException, NoSuchMethodException {
                
        if (object == null) {
            return;
        }
        
        Class cls = object.getClass();  //オブジェクトのClass取得
        Field field = cls.getDeclaredField(fieldName);  //文字列(フィールド名)からFieldオブジェクト取得
        Class fieldType = field.getType();  //フィールドの型取得
        Class [] argTypes = {fieldType};
        Object[] argValues = {fieldValue};
        
        setFieldValueByName(cls, object, fieldName, argTypes, argValues);
    }
    
    public static void setFieldValueByName(Class cls, 
            Object object,
            String fieldName, 
            Class [] argTypes,
            Object [] argValues) 
    throws SecurityException, NoSuchFieldException, IllegalArgumentException, 
    IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        if (object == null)
            return;

        //setメソッド名
        char firstChar = fieldName.charAt(0);
        char uFirstChar = Character.toUpperCase(firstChar);
        String setterMethod = "set"
                + fieldName.replaceFirst(String.valueOf(firstChar),
                        String.valueOf(uFirstChar));
        
        //setメソッド
        Method method = cls.getMethod(setterMethod, argTypes);
        //setメソッド実行(オブジェクト、パラメータ)
        method.invoke(object, argValues);
    }
}


class MyClass {
    private String userName;
    private int age;
    
    public MyClass(String userName, int age) {
        this.userName = userName;
        this.age = age;
    }
    
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
}


実行結果:
****************フィールド値取得*****************
Hello
20
****************フィールド値設定*****************
新しい名だよ
30

簡単に説明します。
上のサンプルは、オブジェクトに対して、文字列で指定するフィールドの値を動的に取得/セットする例です。

1)オブジェクトのClass情報を取得
  MyClass.classやobject.getClass()などで取得します。
2)フィールドの値を取得/セットするためのメソッド名を取得
  例えば、MyClassの"userName"というフィールドの値の取得するメソッド名はgetUserNameです。
3)Class情報から指定するメソッド名のMethod情報を取得
  例:
    Method method = cls.getMethod(setterMethod, argTypes);
4)Method.invokeでメソッドを実行して、フィールドの値を取得/セットします。
  例:
    method.invoke(object, argValues);

有关作者
Syboos.jp編集長AJavaやオープンソース情報の執筆、Webサイトの開発や運営全般の業務に携わる。

Sponsored Link


Comments

用户名 (required)

Email (will not be published) (required)

URL

Evaluation