Javaのリフレクション機能は、実行時にプログラム自身の構造や動作を検査・変更できる強力な仕組みです。この機能を利用することで、クラスのフィールド、メソッド、コンストラクタなどを動的に操作することが可能です。
基本的なクラス情報の取得
リフレクションの主要なクラスは java.lang.reflect パッケージに配置されています。
package com.example.demo;
public class BasicReflection {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> targetClass = Class.forName("java.util.Date");
System.out.println("クラス名: " + targetClass.getSimpleName());
}
}
フィールド情報の取得
リフレクションを使用して、プライベートフィールドを含むすべてのフィールド情報を取得できます。
package com.example.demo;
import java.lang.reflect.Field;
public class FieldInspection {
public static void main(String[] args) throws Exception {
Field[] declaredFields = SampleData.class.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println("フィールド名: " + field.getName());
}
}
}
class SampleData {
private Integer identifier;
protected String label;
public double value;
}
アクセス修飾子の変更
リフレクションにより、privateメンバーへのアクセスも可能になります。
package com.example.demo;
import java.lang.reflect.Field;
public class AccessModifierOverride {
public static void main(String[] args) throws Exception {
SampleData data = new SampleData();
Field idField = SampleData.class.getDeclaredField("identifier");
idField.setAccessible(true);
idField.set(data, 100);
System.out.println("設定値: " + idField.get(data));
}
}
インスタンスの動的生成
実行時にクラスのインスタンスを生成することもできます。
package com.example.demo;
import java.lang.reflect.Constructor;
public class DynamicInstantiation {
public static void main(String[] args) throws Exception {
Constructor<SampleData> constructor = SampleData.class.getConstructor();
SampleData instance = constructor.newInstance();
System.out.println("インスタンス生成完了");
}
}
メソッドの動的呼び出し
リフレクションを使ってクラスのメソッドを実行できます。
package com.example.demo;
import java.lang.reflect.Method;
public class MethodInvocation {
public static void main(String[] args) throws Exception {
SampleData obj = new SampleData();
Method displayMethod = SampleData.class.getMethod("displayMessage");
displayMethod.invoke(obj);
}
}
class SampleData {
public void displayMessage() {
System.out.println("こんにちは、世界!");
}
}
ジェネリクスと型情報
ジェネリクスとリフレクションを組み合わせる際は、型消去の影響を考慮する必要があります。
package com.example.demo;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.LinkedList;
import java.util.Queue;
public class GenericTypeExtraction {
public static void main(String[] args) throws Exception {
Type superClass = GenericQueue.class.getGenericSuperclass();
if (superClass instanceof ParameterizedType) {
Type[] typeArgs = ((ParameterizedType) superClass).getActualTypeArguments();
System.out.println("ジェネリック型: " + ((Class<?>) typeArgs[0]).getName());
}
}
}
class GenericQueue extends LinkedList<Integer> {
// 実装内容
}
例外処理の考慮
リフレクション操作では様々な例外が発生する可能性があるため、適切なエラーハンドリングが必要です。
package com.example.demo;
import java.lang.reflect.Field;
public class ExceptionHandlingDemo {
public static void main(String[] args) {
try {
Field field = String.class.getDeclaredField("value");
field.setAccessible(true);
// 操作処理
} catch (NoSuchFieldException e) {
System.err.println("フィールドが見つかりません");
} catch (SecurityException e) {
System.err.println("セキュリティ制限によりアクセスできません");
} catch (Exception e) {
System.err.println("その他のエラーが発生しました");
}
}
}
リフレクションは強力な機能ですが、過度な使用はコードの保守性やパフォーマンスに悪影響を与える可能性があります。必要な場面で慎重に利用することが重要です。