Java を学び始めると、リフレクション(Reflection)という言葉を耳にするかもしれません。リフレクションを使うと、クラスやメソッドの情報をプログラムが実行中に調べたり、動的に呼び出したり できます。
たとえば、テキストで書かれたクラス名やメソッド名をもとに、そのクラスのメソッドを呼び出すなど、通常はコンパイル時に固まっている部分を実行時に柔軟に扱えるようになる仕組みです。
このページではJava初心者の方が「リフレクションって何だろう?」という疑問を解消できるように解説します。
リフレクションとは?
リフレクションのイメージ
リフレクションの代表的な操作
- クラスやメソッドの情報を取得
- 「このクラスにはどんなメソッドがあるか」を調べる。
- メソッドを動的に呼び出す
- 実行前にはクラス名やメソッド名が分からない状況でも、テキストや設定ファイルから読み込んだ文字列を使って、そのメソッドを呼び出したりできる。
- フィールドの値を取得・設定
- 通常は
obj.fieldName
で直接アクセスするところを、文字列で指定してアクセスできる(制限はある)。
- 通常は
どうやってリフレクションを使うの?
Class オブジェクトを取得する
Java でリフレクションを使う最初のステップは、クラスを表す Class
オブジェクト を取得することです。以下の3つの方法が代表的です。
// 方法1: クラス名から直接 Class<String> c1 = String.class; // 方法2: インスタンスから取得 String str = "Hello"; Class<?> c2 = str.getClass(); // 方法3: forName(完全修飾クラス名) Class<?> c3 = Class.forName("java.lang.String");
Class.forName
は、文字列でクラス名を指定してロードするので、動的にクラスを扱うときに特に便利です。
クラスの情報を取得する
Class
オブジェクトを手に入れると、そこからメソッドやフィールド、コンストラクタなどの情報を取得できます。
Class<?> clazz = Class.forName("java.lang.String"); // 1. メソッド一覧を取得 Method[] methods = clazz.getDeclaredMethods(); // 2. フィールド一覧を取得 Field[] fields = clazz.getDeclaredFields(); // 3. コンストラクタ一覧を取得 Constructor<?>[] constructors = clazz.getDeclaredConstructors();
getDeclaredMethods()
は、そのクラスに定義されているすべてのメソッドを返します。
メソッドを呼び出す方法
リフレクションの強みのひとつは、「文字列を使ってメソッドを探し、そのメソッドを呼び出せる」 ことです。
メソッドの取得
以下は、String
クラスの substring
メソッド(2つの引数を取るバージョン)を取得する例です。
Method substringMethod = String.class.getDeclaredMethod("substring", int.class, int.class);
- 第一引数:メソッド名(
"substring"
)。 - 第二引数以降:メソッドの引数型を順番どおりに指定。
メソッドの呼び出し (invoke)
取得したメソッドを呼び出すには、invoke
メソッドを使います。
String test = "Hello World"; String result = (String) substringMethod.invoke(test, 0, 5); System.out.println(result); // => "Hello"
nvoke
の第一引数:呼び出したいインスタンス(静的メソッドの場合はnull
)。- 第二引数以降:実際にそのメソッドに渡す引数。
注意:
invoke
の戻り値はObject
型なので、適切な型にキャスト(変換)する必要があります。
フィールドへのアクセス
メソッドだけでなく、クラスのフィールド(変数) にアクセスすることもできます。プライベートフィールドにもアクセスできるので強力ですが、セキュリティ面で制限がある場合もあります。
フィールドの取得
Field field = SomeClass.class.getDeclaredField("somePrivateField");
getDeclaredField
にフィールド名を渡して取得。
値の取得と設定
SomeClass obj = new SomeClass(); // プライベートフィールドにアクセス可能にする field.setAccessible(true); // フィールドの値を取得 Object value = field.get(obj); // フィールドに値をセット field.set(obj, "new value");
ステップ5: いつ使うの?メリットと注意点
5-1. メリット
- 動的にクラスやメソッドを読み込める
- 外部の設定ファイルからクラス名を読み込み、メソッドを呼び出せる。
- プラグイン機構や、ソフトウェアの拡張ポイントとして便利。
- 柔軟性が高い
- フレームワーク(Spring, Hibernate, Jackson など)はリフレクションを多用し、柔軟な設定やアノテーション解析を可能にしている。
5-2. デメリット & 注意点
- パフォーマンスが落ちる
- リフレクションによるメソッド呼び出しは、通常のメソッド呼び出しに比べて遅い。
- コードが複雑になる
- 文字列でクラス名やメソッド名を指定するため、型安全性が薄れる(間違った名前を書いてもコンパイルが通る)。
- セキュリティリスク
- プライベートフィールドにアクセスできるなど、想定外の変更を加えられてしまう可能性がある。
- 実際の運用環境ではセキュリティマネージャやアクセス制限がある場合が多い。
リフレクションは初めて見ると少しハードルが高く感じますが、Java で高度なフレームワークを作る際のキモとなる技術のひとつです。最初は「なんだか難しそう…」と思うかもしれませんが、
- 「
Class
オブジェクトを取得する」 - 「メソッドを取得して
invoke
で呼び出す」
というシンプルな流れを押さえるだけでも、リフレクションがどう動くかをイメージできるでしょう。
実際に小さな実験コードを書きながら、クラスやメソッドの情報を取ってみたり、動的に呼び出してみると理解が深まります。ぜひチャレンジしてみてください!