Javaのリフレクションでフィールドを扱ってみる
リフレクションの勉強をします。今回はフィールドに関するリフレクションについて勉強します。
概要
フィールドに関するリフレクションは java.lang.reflect.Field
にまとまっています。
Fieldは、クラスまたはインタフェースについての情報、それらへの動的なアクセス、その単一フィールドを提供します。リフレクトされたフィールドが、クラス(static)フィールドまたはインスタンス・フィールドであることもあります。
テストクラス
Foo.java
package jp.co.sample;
public class Foo {
public String publicField;
private String privateField;
public Integer hoge;
public Double fuga;
static {
System.out.println("static block.");
}
public Foo() {
System.out.println("constructor.");
}
public Foo(String publicField, Integer hoge, Double fuga) {
this.publicField = publicField;
this.hoge = hoge;
this.fuga = fuga;
}
protected Foo(String publicField) {
this.publicField = publicField;
}
Foo(Integer hoge) {
this.hoge = hoge;
}
private Foo(Double fuga) {
this.fuga = fuga;
}
public String getBar() {
return this.publicField;
}
public void setBar(String publicField) {
this.publicField = publicField;
}
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=" + publicField + "]";
}
}
フィールドの取得
フィールドを取得するためのメソッドは以下があります。
メソッド | 戻り値 | 取得可能なアクセス修飾子 |
---|---|---|
Class#getField | Field | public |
Class#getFields | Field | public |
Class#getDeclaredField | Field | すべて |
Class#getDeclaredFields | Field | すべて |
フィールドの型を取得(Field#getType)
Class#getField
で Field
を取得して、Field#getType
で型を取得します。getDeclaredField
ではprivateなフィールドにアクセスすることができます。
@Test public void getFieldでpublicフィールドの型が取得できること() throws Exception { Field field = Foo.class.getField("publicField"); assertThat(field.getType(), is(equalTo(String.class))); } @Test(expected = java.lang.NoSuchFieldException.class) public void getFieldでprivateフィールドの型が取得できないこと() throws Exception { Field field = Foo.class.getField("privateField"); } @Test public void getDeclaredFieldでpublicフィールドの型が取得できること() throws Exception { Field field = Foo.class.getDeclaredField("publicField"); assertThat(field.getType(), is(equalTo(String.class))); } public void getDeclaredFieldでprivateフィールドの型が取得できること() throws Exception { Field field = Foo.class.getDeclaredField("privateField"); assertThat(field.getType(), is(equalTo(String.class))); }
フィールドの名前を取得(Field#getName)
Field#getName
でフィールド名を取得します。
@Test public void getFieldでpublicフィールドの名前が取得できること() throws Exception { Field field = Foo.class.getField("publicField"); assertThat(field.getName(), is("publicField")); }
フィールドの値を取得
Field#get
でフィールドの値を取得します。
@Test public void getでpublicフィールドの値が取得できること1() throws Exception { Foo foo = new Foo("public", 100, 0.11); Field field = foo.getClass().getField("publicField"); assertThat(field.get(foo), is("public")); } @Test public void getでpublicフィールドの値が取得できること2() throws Exception { Foo foo = new Foo("public", 100, 0.11); Field field = foo.getClass().getField("hoge"); assertThat(field.get(foo), is(100)); } @Test public void getでpublicフィールドの値が取得できること3() throws Exception { Foo foo = new Foo("public", 100, 0.11); Field field = foo.getClass().getField("fuga"); assertThat(field.get(foo), is(0.11)); }
フィールドの値を設定
Field#set
でフィールドの値を取得します。
privateなフィールドに関して、デフォルトのリフレクションではsetすることはできませんが、setAccessible(true)
とするとsetできるようになります。これは AccessibleObject
クラスの以下の仕様によるものです。
リフレクトされたオブジェクトでaccessibleフラグを設定すると、十分な特権を持つ高度なアプリケーション(Javaのオブジェクトの直列化やその他の持続性メカニズムなど)は、通常は禁止されている方法でオブジェクトを操作できます。デフォルトでは、リフレクトされたオブジェクトはアクセス可能ではありません。
@Test public void setでpublicフィールドの名前がセットできること() throws Exception { Foo foo = new Foo("public", 100, 0.11); Field field = foo.getClass().getDeclaredField("publicField"); field.set(foo, "change!"); assertThat(field.get(foo), is("change!")); } @Test(expected = java.lang.IllegalAccessException.class) public void setでprivateフィールドの名前がセットできないこと() throws Exception { Foo foo = new Foo("public", 100, 0.11); Field field = foo.getClass().getDeclaredField("privateField"); field.set(foo, "change!"); assertThat(field.get(foo), is("change!")); } @Test public void setでprivateフィールドの名前がセットできること() throws Exception { Foo foo = new Foo("public", 100, 0.11); Field field = foo.getClass().getDeclaredField("privateField"); field.setAccessible(true); field.set(foo, "change!"); assertThat(field.get(foo), is("change!")); }