どんなものでも抜け道はあるのである。
javaでは通常、privateメソッドは、他のクラスから呼ぶことはできない。しかしリフレクションを使えば、それができてしまう。
以下に、任意のオブジェクトの、privateメソッドを呼びだすサンプルプログラムを示す。
public class Hoge { private int sum(int a, int b) { return a+b; } } public class ReflectUtil { public static Object forceInvoke(Object obj, String methodName, Object... args) throws NoSuchMethodException { try { Class c = obj.getClass(); Class[] argClasses = null; if (args!=null) { List<Class> argClassList = new ArrayList<Class>(); for (Object object : args) { argClassList.add(object.getClass()); } argClasses = argClassList.toArray(new Class[0]); } Method m = null; try { m = c.getDeclaredMethod(methodName, argClasses); } catch (NoSuchMethodException e) { try { m = c.getMethod(methodName, argClasses); } catch (NoSuchMethodException e1) { throw e1; } } boolean isAccessible = m.isAccessible(); m.setAccessible(true); Object result = m.invoke(obj, args); m.setAccessible(isAccessible); return result; } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return null; } public static void main(String[] args) throws NoSuchMethodException { Hoge hoge = new Hoge(); System.out.println(forceInvoke(hoge, "sum", 100,200)); } }
この例では、Hogeクラスのprivateメソッド、sumを呼び出した。
実行結果は以下の通りであり、privateなメソッドにアクセスできていることが分かる。
300
privateメソッドにアクセスするためのポイントは二つある。
一つは、Class#getDeclaredMethodを用いて、呼び出したいメソッドのMethodオブジェクトを得ることである。ClassオブジェクトからMethodオブジェクトを得る方法としては、もうひとつClass#getMethodがあるが、こちらはpublicメソッドのみしか取得できない。Class#getDeclaredMethodなら、privateメソッドも含めて取得することができる。
もう一つは、java.lang.reflect.Method#setAccessible を用いて、呼び出したいMethodオブジェクトのaccessibleをtrueにすることである。accessibleの値は、publicメソッドであろうと、privateメソッドであろうと、デフォルトでfalseが設定されているようである。accessibleがfalseかつprivateなメソッドオブジェクトをinvokeしようとすると例外になる。ちなみに、コンストラクタのaccessibleを設定しようとしても例外が発生する。
今回はprivateメソッドを無理矢理呼び出す方法を紹介したが、有効な利用方法があるのかどうかはよく分からない。