こんにちは。「Javaを復習する初心者」です。
今回はリフレクションを使って、privateであるフィールドにアクセスする方法を確認しました。
あるクラスにprivateであるフィールドが定義されているとします。クラス外から、このフィールドを直接操作することは通常はできません。しかし、リフレクションと呼ばれるAPIを使用すると値を操作することができます。
クラス定義
今回は以下のクラスを用意しました。
MyInteger
public class MyInteger {
private int number;
public void add(int n) {
number += n;
}
public int getNumber() {
return number;
}
}
このクラスのフィールドnumberはアクセス修飾子がprivateです。そのため、このクラス外からは直接参照することはできません。ですが、単体テスト等で直接値を操作したい場合、リフレクションを使って値を変更することができます。
フィールドにアクセス
以下、一例です。
ソース
MyInteger myInteger = new MyInteger();
System.out.println(myInteger.getNumber());
myInteger.add(2);
System.out.println(myInteger.getNumber());
Field field = null;
try {
field = MyInteger.class.getDeclaredField("number");
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
field.setAccessible(true);
try {
field.set(myInteger, 1);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
System.out.println(myInteger.getNumber());
実効結果は以下です。
結果
0
2
1
上記結果の0と2は普通の方法を実行した結果です。インスタンス生成時はint型フィールドの初期値は0です。なので最初に0が表示されています。次に、クラスに用意されているメソッドを使ってます。「add(2)」と記述しているのでフィールドに2が加算されています。
そのあとにフィールドの値を1にするのがこのプログラムの目的です。クラスの作り方から通常の方法ではできません。そこでリフレクションという機能を使います。
まず、Fieldクラスを用意します。[クラス名].class.getDeclaredField([フィールド名])という記述でインスタンスを格納します。[クラス名].classで取得できるのはClassクラスのインスタンスです。こういう記述方法があるということしか、わかりませんでした。ClassクラスにはgetDeclaredFieldメソッドが用意されています。このメソッドでフィールドの情報を持つFieldクラスのインスタンスが取得できるようです。指定された名前のフィールドがない場合は、NoSuchFieldExceptionが発生します。
privateフィールドにアクセスする場合は、「field.setAccessible(true);」というようにsetAccessibleメソッドを呼び出します。引数にtrueを指定することでアクセスが可能になります。
具体的に値を設定している個所は「field.set(myInteger, 1);」です。このsetメソッドの引数の定義はset(Object obj, Object value)です。第1引数にインスタンスを指定し、第2引数に値を指定することで、そのインスタンスのフィールドの値を設定することができます。フィールドに1を設定したので、出力結果の最後に1と表示されています。