リフレクションの基礎
クラス情報の取得には主に以下の3つの手法がある。
public class ReflectionTest {
public void setup() {
// テスト前処理
}
public void demonstrateClassRetrieval() throws ClassNotFoundException {
// 文字列からクラス情報を取得 - 設定ファイル読み込みに適す
Class<?> clazz1 = Class.forName("com.example.model.User");
// クラスリテラルから取得 - メソッド引数等に利用
Class<User> clazz2 = User.class;
// インスタンスから取得
Class<? extends User> clazz3 = new User().getClass();
// 同一性検証
assert clazz1 == clazz2;
assert clazz2 == clazz3;
}
public void teardown() {
// テスト後処理
}
}
メンバー要素へのアクセス
public class MemberAccessDemo {
public static void main(String[] args) throws Exception {
Class<User> userClass = User.class;
// フィールド操作
// Field publicField = userClass.getField("username"); // publicフィールドのみ
// Field[] publicFields = userClass.getFields(); // 全publicフィールド
// Field privateField = userClass.getDeclaredField("password"); // アクセス修飾子に関わらず取得
// Field[] allFields = userClass.getDeclaredFields(); // 全フィールド取得
// privateField.setAccessible(true); // privateフィールドへのアクセス許可
// コンストラクタ操作
// Constructor<User> constructor = userClass.getConstructor(String.class, String.class);
// User userInstance = constructor.newInstance("admin", "secret");
// User defaultUser = userClass.newInstance(); // 非推奨だが可能
// メソッド操作
// User target = new User();
// Method setUsername = userClass.getMethod("setUsername", String.class);
// Method setPassword = userClass.getMethod("setPassword", String.class);
// setUsername.invoke(target, "newuser");
// setPassword.invoke(target, "newpass");
// クラス情報の取得
// String fullName = userClass.getName(); // 完全修飾クラス名
// Method[] allMethods = userClass.getMethods(); // 全publicメソッド
}
}
実践的なリフレクションの応用
設定ファイルに基づく動的オブジェクト生成の例を示す。
サービスクラス
// Instructor.java
public class Instructor {
public void conductLesson() {
System.out.println("講師が授業を行っています");
}
}
// Learner.java
public class Learner {
public void attendClass() {
System.out.println("学習者が勉強しています");
}
}
設定ファイル
# config/application.conf
targetClass=Learner
actionMethod=attendClass
実行クラス
public class DynamicExecutor {
public static void main(String[] args) throws Exception {
// クラスローダーを用いた設定ファイル読み込み
ClassLoader loader = DynamicExecutor.class.getClassLoader();
InputStream configStream = loader.getResourceAsStream("config/application.conf");
// プロパティ解析
Properties config = new Properties();
config.load(configStream);
String className = config.getProperty("targetClass");
String methodName = config.getProperty("actionMethod");
// 動的インスタンス生成
Class<?> targetClass = Class.forName(className);
Object instance = targetClass.newInstance();
// メソッド実行
Method action = targetClass.getMethod(methodName);
action.invoke(instance);
}
}
アノテーションの理解と活用
アノテーションの種類
/*
* アノテーションの分類:
* 1. ドキュメンテーション用: @param, @return, @author 等のJavadoc関連
* 2. 標準提供アノテーション: @Override, @Deprecated, @SuppressWarnings
* 3. メタアノテーション: @Target, @Retention, @Documented, @Inherited
* 4. カスタムアノテーション: ユーザー定義
*/
カスタムアノテーションの作成
列挙型定義
public enum ThemeColor {
RED, GREEN, YELLOW, BLUE
}
関連アノテーション
public @interface RelatedInfo {
String description() default "";
}
主アノテーション定義
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Configuration {
String identifier() default "default";
int version() default 1;
ThemeColor theme() default ThemeColor.BLUE;
RelatedInfo related() default @RelatedInfo;
String[] tags() default {};
}
アノテーションの使用と解析
@Configuration(identifier = "main-module", version = 2)
public class AnnotationProcessor {
public static void main(String[] args) throws NoSuchMethodException {
Class<AnnotationProcessor> targetClass = AnnotationProcessor.class;
// クラスレベルのアノテーション解析
Configuration classConfig = targetClass.getAnnotation(Configuration.class);
// メソッドレベルのアノテーション解析
Method targetMethod = targetClass.getMethod("execute");
Configuration methodConfig = targetMethod.getAnnotation(Configuration.class);
// アノテーション属性値の取得
String id = classConfig.identifier();
int ver = methodConfig.version();
System.out.println("ID: " + id + ", Version: " + ver);
}
@Configuration(tags = {"execution", "process"})
public void execute() {
// 処理内容
}
}