Javaその他

Javaのリフレクションを利用してみた(メソッド編)

リフレクションを利用すると、クラス名・メソッド名・引数を指定して、指定したクラスのメソッドを動的に実行することができるため、メソッド名・引数・戻り値が全て同一でクラス名だけが違うクラスが複数存在する場合に、1つのプログラムで処理することができる。

今回は、リフレクションを利用し、引数や戻り値がある場合、privateメソッドの場合、staticメソッドの場合、コンストラクタに引数がある場合を含むようなサンプルプログラムを作成したので、共有する。

前提条件

下記記事のIntelliJ IDEA Community版をダウンロード済であること。

IntelliJ IDEAをインストールしてみた「IntelliJ IDEA(インテリジェイ アイディア)」という、Eclipseと同等の機能をもつJava用統合開発環境を使って、Sp...

また、下記のように、「demoJava」というJavaプロジェクトを作成済であること。
demoJavaプロジェクト

なお、IntelliJ IDEA上でJavaプロジェクトを作成する方法については、IntelliJ IDEA Community版をダウンロードする記事内の、「IntelliJ IDEA上でのJavaプロジェクトの作成・実行」を参照のこと。



リフレクションを利用したサンプルプログラムの作成と実行

今回作成したサンプルプログラムの構成は以下の通り。
リフレクションを利用したサンプルプログラムの構成

今回は、「CallSampleMethod.java」で「SampleMethod.java」「SampleMethod2.java」の各メソッドの呼び出しを行っている。それぞれのプログラムの内容は以下の通り。

package demo.java;

public class SampleMethod {

    /**
     * コンストラクタ
     */
    public SampleMethod(){}

    /**
     * method1の定義
     */
    public void method1(){
        System.out.println("method1 called.");
    }

    /**
     * method2の定義
     * @return 返却用文字列
     */
    public String method2(){
        return "method2 called.";
    }

    /**
     * method3の定義
     * @param str 文字列
     * @param num 数値
     */
    public void method3(String str, Integer num){
        System.out.println("method 3 called. str = "
                + str + ", int = " + num);
    }

    /**
     * method4の定義
     * @param str 文字列
     * @return 返却用文字列
     */
    private String method4(String str){
        return "method4 called. str = " + str;
    }

    /**
     * method5の定義
     * @param str 文字列
     * @return 返却用文字列
     */
    public static String method5(String str){
        return "method5 called. str = " + str;
    }
}
package demo.java;

public class SampleMethod2 {

    /** クラス内で保持する文字列 */
    private String str;

    /**
     * コンストラクタ
     * @param str 文字列
     */
    public SampleMethod2(String str){
        this.str = str;
    }

    /**
     * method6の定義
     * @param num 文字列
     * @return 返却用文字列
     */
    public String method6(int num){
        return str + "str" + num;
    }
}
削除または保存していないWordドキュメントの復元方法【4DDiG Windowsデータ復元】ワード(Word)データ等のファイルを誤って削除してしまった場合は、通常はデータの復元ができませんが、4DDiGというソフトウェアを利用...
package demo.java;

import java.lang.reflect.Method;

public class CallSampleMethod {

    public static void main(String[] args){
        try{
            //コンストラクタに引数がないクラスのインスタンスを生成
            //Class.forName(クラスのフルパス)でクラスオブジェクトを生成後、
            //getDeclaredConstructor().newInstance()によりインスタンスを生成
            Class clazz = Class.forName("demo.java.SampleMethod");
            Object obj = clazz.getDeclaredConstructor().newInstance();

            //引数・戻り値がないpublicメソッドの呼び出し
            //getDeclaredMethodメソッドの第1引数にメソッド名を指定して
            //メソッドを生成後、invokeメソッドを呼び出す
            System.out.println("*** SampleMethod method1 calling ***");
            Method method1 = clazz.getDeclaredMethod("method1");
            method1.invoke(obj);
            System.out.println();

            //引数がなく、戻り値があるpublicメソッドの呼び出し
            //戻り値を取得するには、invokeメソッドの戻り値を、指定したメソッドの
            //戻り値の型でキャストする
            System.out.println("*** SampleMethod method2 calling ***");
            Method method2 = clazz.getDeclaredMethod("method2");
            String str2 = (String)method2.invoke(obj);
            System.out.println("method2の戻り値 : " + str2);
            System.out.println();

            //引数があり、戻り値がないpublicメソッドの呼び出し
            //引数の型をgetDeclaredMethodメソッドの第2引数以降で指定し、
            //invokeメソッドの第2引数以降で引数の値を指定する
            System.out.println("*** SampleMethod method3 calling ***");
            Method method3 = clazz.getDeclaredMethod(
                    "method3", String.class, Integer.class);
            method3.invoke(obj, "str3", 3);
            System.out.println();

            //引数・戻り値があるprivateメソッドの呼び出し
            //privateメソッドを呼び出すにはgetDeclaredMethodでメソッドでメソッド
            //を呼び出し、setAccessibleをtrueにする
            System.out.println("*** SampleMethod method4 calling ***");
            Method method4 = clazz.getDeclaredMethod("method4", String.class);
            method4.setAccessible(true);
            String str4 = (String)method4.invoke(obj, "str4");
            System.out.println("method4の戻り値 : " + str4);
            System.out.println();

            //引数・戻り値があるstaticメソッドの呼び出し
            //staticメソッドを呼び出すにはgetDeclaredMethodでメソッドでメソッド
            //を呼び出し、invokeメソッドの第1引数をnullにする
            System.out.println("*** SampleMethod method5 calling ***");
            Method method5 = clazz.getDeclaredMethod("method5", String.class);
            String str5 = (String)method5.invoke(null, "str5");
            System.out.println("method5の戻り値 : " + str5);
            System.out.println();

            //コンストラクタに引数があるクラスのインスタンスを生成
            //getDeclaredConstructorメソッドの引数に、コンストラクタの引数の型を指定し、
            //newInstanceメソッドの引数に、コンストラクタの引数の値を指定する
            Class clazz2 = Class.forName("demo.java.SampleMethod2");
            Object obj2 = clazz2.getDeclaredConstructor(String.class)
                    .newInstance("method6 called. str = ");

            //コンストラクタに引数があるクラスのメソッドの呼び出し
            System.out.println("*** SampleMethod2 method6 calling ***");
            Method method6 = clazz2.getDeclaredMethod("method6", int.class);
            String str6 = (String)method6.invoke(obj2, 6);
            System.out.println("method6の戻り値 : " + str6);

        }catch(Exception e){
            System.out.println(e);
        }
    }
}

さらに、その実行結果は以下の通り。
リフレクションを利用したサンプルプログラムの実行結果

要点まとめ

  • Class.forName(クラスのフルパス)でクラスオブジェクトの生成が行える。
  • クラスオブジェクトのgetDeclaredConstructorメソッドを呼び出し後、newInstanceメソッドを呼び出すことにより、クラスのインスタンス生成が行える。
  • クラスオブジェクトのgetDeclaredMethodメソッドを呼び出し後、invokeメソッドを呼び出すことにより、メソッドの呼び出しが行える。