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でスーパークラスのメソッドへのアクセス
- リフレクションのエラーハンドリング関連