今度は非publicメンバに対するリフレクションです。非publicメンバに対しては、getDeclaredXXXXというメソッドが用意されています。対応表にすると以下のようになります。
公開レベル |
メンバ |
列挙 |
名前指定 |
public |
メソッド |
java.lang.Class#getMethods() |
java.lang.Class#getMethod(String,Class[]) |
public |
フィールド |
java.lang.Class#getFields() |
java.lang.Class#getField(String) |
public |
コンストラクタ |
java.lang.Class#getConstructors() |
java.lang.Class#getConstructor(Class[]) |
非public |
メソッド |
java.lang.Class#getDeclaredMethods() |
java.lang.Class#getDeclaredMethod(String,Class[]) |
非public |
フィールド |
java.lang.Class#getDeclaredFields() |
java.lang.Class#getDeclaredField(String) |
非public |
コンストラクタ |
java.lang.Class#getDeclaredConstructors() |
java.lang.Class#getDeclaredConstructor(Class[]) |
非publicと書くとpublic以外のメンバが返されるのかなと誤解させてしまいますが、返されるメンバはそのクラスに直接定義されたメンバが返されます。getXXX()とgetDeclaredXXX()の違いは、公開インターフェイスとなるpublicな全てのメンバを返すのか、そのクラスの直接定義されたメンバを返すのかの違いになります。
非publicなメンバに対してpublicメンバ同様実行などが可能ですが、必要な手続きがあります。
setAccessibleというメソッドをinvoke前に実行しています。これはアクセス元から見て通常ではアクセスできないメンバに対してアクセスが出来るようにする為のフラグの設定です。セキュリティマネージャが存在しても極力設定できるように特権で設定しています。
実際には同一クラス内のメンバを取得している為、上記例では不要な処理ですが、通常自分自身のメンバを取得する為に使用するケースは少なく、様々なクラスのメンバを取得して実行するケースが殆どなので、このようにして使うと覚えておくとよいでしょう。
ちなみにターゲットとなるクラスの親クラスのprotectedなメソッドを取得するには、ちょっと工夫が必要です。ターゲットのクラスに対してgetMethodを使ってもpublicではないので取得できません。また直接定義されているメンバではないのでgetDeclaredMethodでも取得できません。こういうときは、ターゲットのクラスの親クラスを参照します。実際には以下のようなコードで取得します。
指定したメソッドが見つからない場合、NoSuchMethodExceptionがスローされるのでその例外をキャッチした場合はターゲットのクラスの親クラスを取得しています。親クラスがnullの場合Object型になっているのでそれ以上は諦めます。
このように公開レベルを無視してメンバの処理ができますが、カプセル化を破壊する事になりますので、使用する時は注意が必要です。