1. 導入:なぜメソッドを「動的」に取得する必要があるのか?
Javaで開発をしていると、プログラムの実行中にクラスの構造(メソッドやフィールド)を調べたり、実行したりしたい場面に出くわします。これを「リフレクション」と呼びます。
例えば、フレームワークの自動設定や、ライブラリでのテスト実行、あるいは特定の条件で動的にメソッドを呼び出したい場合、これらのメソッドを使い分ける知識が不可欠です。これらを正しく理解することで、コードの柔軟性が飛躍的に向上します。
2. 基礎知識:リフレクションとは何か
Javaは通常、コンパイル時にクラスの構造が決定されますが、リフレクションを使うと、プログラム実行中(ランタイム)にクラス情報を「鏡に映すように」覗き見ることができます。
今回紹介する4つのメソッドは、対象クラスから特定の処理を行うための「Methodオブジェクト」を取得するための入り口です。
3. 実装/解決策:4つのメソッドの使い分け
これらのメソッドは、大きく分けて2つの軸で分類できます。
軸1:継承関係を含めるか?
・getMethods系: 親クラスのpublicメソッドも取得する。
・getDeclaredMethods系: そのクラスで定義されたメソッドのみ取得する(privateも含む)。
軸2:単一取得か?リスト取得か?
・getMethod系: 名前と引数の型を指定して1つ取得する。
・getMethods系: 全てのメソッドを配列で取得する。
使い分けの鉄則:
・外部から呼び出されるAPIを作るときは「getMethods」
・クラス内部のprivateメソッドをテストや解析でこじ開けたいときは「getDeclaredMethods」を使います。
4. サンプルプログラム
以下のコードをコピーして、実際に動かしてみてください。
import java.lang.reflect.Method;
public class ReflectionSample {
public void publicMethod() { System.out.println(“公開メソッド”); }
private void privateMethod() { System.out.println(“非公開メソッド”); }
public static void main(String[] args) throws Exception {
Class
// 1. publicなメソッドを検索(継承先含む)
Method m1 = clazz.getMethod(“publicMethod”);
m1.invoke(new ReflectionSample());
// 2. クラスで宣言されたすべてのメソッドを検索(private含む)
Method m2 = clazz.getDeclaredMethod(“privateMethod”);
// privateメソッドを呼ぶにはアクセス許可が必要
m2.setAccessible(true);
m2.invoke(new ReflectionSample());
// 3. すべてのメソッドを一覧表示
System.out.println(“— メソッド一覧 —“);
for (Method m : clazz.getDeclaredMethods()) {
System.out.println(“メソッド名: ” + m.getName());
}
}
}
5. 応用・注意点:現場で陥りやすい罠
現場でリフレクションを使う際に最も注意すべき点は、「パフォーマンス」と「セキュリティ」です。
パフォーマンスの低下: リフレクションは通常のメソッド呼び出しよりもオーバーヘッドが大きいです。頻繁に呼び出すループ内での使用は避けましょう。
setAccessible(true)の危険性: privateメソッドを強制的に呼び出すと、カプセル化(情報の隠蔽)が崩れます。これにより、将来的なライブラリのアップデートでメソッド名が変わった際に、コンパイルエラーにならず実行時エラー(NoSuchMethodException)が発生し、バグの発見が遅れる原因になります。
どうしても動的な呼び出しが必要な場合は、可能であれば「MethodHandle」や「VarHandle」といったJava 7以降の高速な代替手段を検討することも、シニアエンジニアへの第一歩です。

コメント