こんにちは。ハンドルネーム「Javaを復習する初心者」です。このサイトはプログラミング言語Javaの復習・学習をするブログです。プログラムの開発・実行はEclipseで行ってます。
スポンサーリンク
お知らせ
  • 参考文献のページ作りました。
  • Amazon.co.jpアソシエイトに参加していますが、参考文献の紹介はもしもアフィリエイトに統一しました。
  • 2016年10月9日からは投稿ペースを落とします。週1回くらいにする予定です。
スポンサーリンク

リフレクションでprivateフィールドにアクセスする

こんにちは。「Javaを復習する初心者」です。今回はリフレクションを使って、privateであるフィールドにアクセスする方法を確認しました。

あるクラスにprivateであるフィールドが定義されているとします。クラス外から、このフィールドを直接操作することは通常はできません。しかし、リフレクションと呼ばれるAPIを使用すると値を操作することができます。

クラス定義

今回は以下のクラスを用意しました。

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と表示されています。