HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

java.lang.reflect.AccessibleObject#setAccessible()の影響範囲

自分は、設定を変更したら元に戻さないときがすまない性分なので、何気なく次のようなコードを書いていた。

    private static void printPrivateFieldValue(Object obj, String name) throws Exception {
        Field field = obj.getClass().getDeclaredField(name);
        boolean oldAccessible = field.isAccessible();
        field.setAccessible(true);
        try {
            System.out.println(field.get(obj));
        } finally {
            field.setAccessible(oldAccessible);
        }
    }

しかし、そもそもgetDeclaredField()メソッドが返すFieldオブジェクトは同一のものなのだろうか?とふと思い、確認してみることにした。

import java.lang.reflect.Field;

public class Main {

    /**
     * @param args
     * @throws Exception 
     */
    public static void main(String[] args) throws Exception {
        Hoge hoge = new Hoge();

        Field field1 = hoge.getClass().getDeclaredField("msg");
        System.out.println("field(1): " + System.identityHashCode(field1));
        System.out.println("field(1): " + field1.isAccessible());

        field1.setAccessible(true);

        System.out.println("field(1): " + field1.isAccessible());

        Field field2 = hoge.getClass().getDeclaredField("msg");
        System.out.println("field(2): " + System.identityHashCode(field2));
        System.out.println("field(2): " + field2.isAccessible());
    }

}

クラスHogeはこんな感じ。

public class Hoge {

    private String msg = "Hello World";

    public void hoge() {
        System.out.println(msg);
    }

}

その実行結果。

field(1): 11394033
field(1): false
field(1): true
field(2): 4384790
field(2): false

どうも、自分の思い込みだったようで。getDeclaredField()メソッドは、その呼び出しごとに異なるFieldオブジェクトを返し、accessibleかどうかの変更に対する影響範囲はそのFieldオブジェクト内に閉じているらしい。
ということで、いちいち変更を元に戻す必要はなく、冒頭のコードは次のように簡潔にできる。

    private static void printPrivateFieldValue(Object obj, String name) throws Exception {
        Field field = obj.getClass().getDeclaredField(name);
        field.setAccessible(true);
        System.out.println(field.get(obj));
    }