技術メモ

技術メモ

ラフなメモ

Javaのリフレクションでメソッドを試す

リフレクションの勉強をします。今回はメソッドに関するリフレクションについて勉強します。

概要

メソッドに関するリフレクションは java.lang.reflect.Method にまとまっています。

Methodは、クラスまたはインタフェース上の単一のメソッドに関する情報とそのアクセスを提供します。リフレクトされたメソッドは、クラス・メソッドまたはインスタンス・メソッド(抽象メソッドを含む)になります。

テストクラス

Foo.java

package jp.co.sample;

public class Foo {
    private String bar;
    private Integer hoge;
    private Double fuga;

    static {
        System.out.println("static block.");
    }

    public Foo() {
        System.out.println("constructor.");
    }

    protected Foo(String bar) {
        this.bar = bar;
    }

    Foo(Integer hoge) {
        this.hoge = hoge;
    }

    private Foo(Double fuga) {
        this.fuga = fuga;
    }

    public String getBar() {
        return this.bar;
    }

    public void setBar(String bar) {
        this.bar = bar;
    }

    public int publicMethod() {
        return 1;
    }

    public int publicMethod(int num) {
        return 1 * num;
    }

    protected int protectedMethod() {
        return 2;
    }

    int defaultMethod() {
        return 3;
    }

    private int privateMethod() {
        return 4;
    }

    public static String staticMethod() {
        return "static";
    }

    @Override
    public String toString() {
        return "Foo [bar=" + bar + "]";
    }
}

Methodの取得

Methodクラスは Class#getMethod()Class#getDeclaredMethod() などで取得できます。

2つのメソッドの違いは主に以下です。

メソッド 取得可能なアクセス修飾子 取得可能なクラス
getMethod public 自クラスとスーパークラス
getDeclaredMethod すべて 自クラス

確認用テストコード

    @Test
    public void getMethodでpublicMethodメソッドのMethodオブジェクトが取得できること() throws Exception {
        Method method = Foo.class.getMethod("publicMethod");
        assertThat(method.toString(), is("public int jp.co.sample.Foo.publicMethod()"));
    }

    @Test(expected = NoSuchMethodException.class)
    public void getMethodでprotectedMethodメソッドのMethodオブジェクトが取得できないこと() throws Exception {
        Method method = Foo.class.getMethod("protectedMethod");
    }

    @Test(expected = NoSuchMethodException.class)
    public void getMethodでdefaultメソッドのMethodオブジェクトが取得できないこと() throws Exception {
        Method method = Foo.class.getMethod("defaultMethod");
    }

    @Test(expected = NoSuchMethodException.class)
    public void getMethodでprivateMethodメソッドのMethodオブジェクトが取得できないこと() throws Exception {
        Method method = Foo.class.getMethod("privateMethod");
    }

    @Test
    public void getDeclaredMethodでpublicMethodメソッドのMethodオブジェクトが取得できること() throws Exception {
        Method method = Foo.class.getDeclaredMethod("publicMethod");
        assertThat(method.toString(), is("public int jp.co.sample.Foo.publicMethod()"));
    }

    public void getDeclaredMethodでprotectedMethodメソッドのMethodオブジェクトが取得できること() throws Exception {
        Method method = Foo.class.getDeclaredMethod("protectedMethod");
        assertThat(method.toString(), is("protected int jp.co.sample.Foo.protectedMethod()"));
    }

    public void getDeclaredMethodでdefaultメソッドのMethodオブジェクトが取得できること() throws Exception {
        Method method = Foo.class.getDeclaredMethod("defaultMethod");
        assertThat(method.toString(), is("int jp.co.sample.Foo.defaultMethod()"));
    }

    public void getDeclaredMethodでprivateMethodメソッドのMethodオブジェクトが取得できること() throws Exception {
        Method method = Foo.class.getDeclaredMethod("privateMethod");
        assertThat(method.toString(), is("private int jp.co.sample.Foo.privateMethod()"));
    }

Methodの呼び出し

メソッドの呼び出しは Method#invoke を使います。

このMethodオブジェクトによって表される基本となるメソッドを、指定したオブジェクトに対して指定したパラメータで呼び出します。

使い方はテストコードにまとめました。実際に使う場合にどのようになるのか知るのが一番よさそうです。

    @Test
    public void invokeで引数なしのインスタンスメソッドを実行() throws Exception {
        Foo foo = Foo.class.getConstructor().newInstance();
        Method method = Foo.class.getMethod("publicMethod");
        int ret = (int) method.invoke(foo);
        assertThat(ret, is(1));
    }

    @Test
    public void invokeで引数ありのインスタンスメソッドを実行() throws Exception {
        Foo foo = Foo.class.getConstructor().newInstance();
        Method method = Foo.class.getMethod("publicMethod", int.class);
        int ret = (int) method.invoke(foo, 5);
        assertThat(ret, is(5));
    }

    @Test
    public void invokeで引数なしのクラスメソッドを実行() throws Exception {
        Method method = Foo.class.getMethod("staticMethod");
        String ret = (String) method.invoke(null);
        assertThat(ret, is("static"));
    }

やり残したこと

  • 可変長引数のメソッドの呼び出し
  • getMethodとgetDeclaredMethodでスーパークラスのメソッドへのアクセス
  • リフレクションのエラーハンドリング関連