アクセッサメソッドを使わずにprivateフィールドを取得したり書き換える
こんなことできると思いますか?
結論!!
できます!!
できるんです。
こんなこと可能にするのはリフレクションを使用します。
リフレクションとは・・・
指定したクラスのフィールドやメソッドやコンストラクタの情報を
探したり、使用したり、書き換えたりします。
基本的な使い方を見てみます。
public class Ref { public String sayHello() { return "Hello World"; } }
なんの変哲も無いクラスを作成します。
こいつを呼び出すと"Hello World"をかえします。
実際に呼び出してみます
import java.lang.reflect.Method; public class Reflection1 { public static void main(String[] args) { try { Class c = Class.forName("Ref"); Method method = c.getMethod("sayHello", null); Object result = method.invoke(c.newInstance(), null); System.out.println(result); } catch (Exception e) { e.printStackTrace(); System.out.println("例外発生"); } } }
これを実行するとHello Worldがコンソールに出力されます。
もし、指定したメソッドが無かっり
クラスが存在しなかったりした場合は例外が投げられます。
もし呼び出すクラスがパッケージ内にある場合は
絶対パスを指定する必要があります。
getMethodの第二引数はパラメータ
invokeの第二引数は呼び出すメソッドの引数を指定します。
詳しくはJavaAPIを参照してください。
で、ひねくれもののdamePGは思いました。
「なんとかprivateのフィールド情報を取得して書き換えできないかなぁ・・・・」
試験としてこのようなクラスを用意しました。
public class Property { private int id = 1; private String name = "damePG"; private String pass = "damedame"; }
うを!!!
完全に守られてます。
ドラクエで言うとメタルスライム級の防御力です。
でもね、ドラクエでもFFでも漫画でも
現実社会でも完全防御を打ち崩す必殺技が
必ず存在します。
Javaもきっとあるはず。
で結論打ち崩しました。
コードはこちら
import java.lang.reflect.Field; public class Reflection2 { private static Field f; static { try { f = Property.class.getDeclaredField("id"); } catch (SecurityException e) { e.printStackTrace(); throw new RuntimeException(e); } catch (NoSuchFieldException e) { e.printStackTrace(); throw new RuntimeException(e); } } public static void main(String[] args) throws SecurityException,NoSuchFieldException, IllegalArgumentException, IllegalAccessException{ Property p = new Property(); f.setAccessible(true); f.set(p, 2); System.out.println(f.get(p)); } }
上から追っていきます。
まずstaticなFieldクラスの変数を用意します。
次にstatic初期化子でどこのクラスのなんていうフィールドかを書きます。(try-catchの中)
mainメソッドでFieldクラスのメソッドを駆使します。
(詳細はJavaAPIで調べてください)
これを実行すれば、idには2が入ります。
あまり現場では使用しないと思いますが、
たまにはこういうのもいいです。
ひょんなことからリフレクションの話題になったので
一回やってみました。
改めて、APIの大切さをまじまじ感じた
damePGでした。
あるとおもいます!!