Javaリフレクションの基本と実践

Javaのリフレクション(Reflection)は、実行時にクラスやオブジェクトに関する情報を動的に取得・操作するための強力な機能です。これにより、コンパイル時には不明なクラスに対しても、そのフィールドやメソッドにアクセスしたり、インスタンスを生成したりできます。

Classオブジェクトの取得方法

リフレクションの中心となるのはjava.lang.Classクラスです。各クラスはJVM上でただ一つのClassオブジェクトを持ち、そのクラスの構造情報を保持しています。Classオブジェクトは以下の3つの方法で取得可能です。

  • ClassName.class:コンパイル時に型がわかっている場合
  • object.getClass():既存のオブジェクトから取得
  • Class.forName("完全修飾クラス名"):文字列から動的にロード
Class<?> clazz1 = String.class;
Class<?> clazz2 = "example".getClass();
Class<?> clazz3 = Class.forName("java.lang.String");

System.out.println(clazz1); // class java.lang.String
System.out.println(clazz2); // class java.lang.String
System.out.println(clazz3); // class java.lang.String

主要なリフレクションAPI

Classクラスには、フィールド、メソッド、コンストラクタ、継承関係などを取得するための多数のメソッドが用意されています。

メソッド説明
getFields()publicフィールド(継承含む)を取得
getDeclaredFields()宣言されたすべてのフィールド(アクセス修飾子問わず、継承除く)
getMethods()publicメソッド(継承含む)を取得
getDeclaredMethods()宣言されたすべてのメソッド(アクセス修飾子問わず、継承除く)
getConstructors()publicコンストラクタを取得
getDeclaredConstructors()すべてのコンストラクタ(private含む)を取得
getSuperclass()スーパークラスのClassオブジェクトを取得
getInterfaces()実装インターフェースを取得

メソッドの動的呼び出し

Methodクラスを使用すると、実行時に任意のメソッドを呼び出すことができます。プライベートメソッドの場合はsetAccessible(true)が必要です。

Class<?> studentClass = Class.forName("Reflection.Student");
Object instance = studentClass.getDeclaredConstructor().newInstance();

// publicメソッドの呼び出し
Method publicMethod = studentClass.getMethod("StudentPublicMethod", String.class);
String result1 = (String) publicMethod.invoke(instance, "hello");
System.out.println(result1); // hello

// privateメソッドの呼び出し
Method privateMethod = studentClass.getDeclaredMethod("StudentPrivateMethod", String.class);
privateMethod.setAccessible(true);
String result2 = (String) privateMethod.invoke(instance, "world");
System.out.println(result2); // world

フィールドへのアクセス

同様に、Fieldクラスを使えば、フィールドの値を読み書きできます。プライベートフィールドもsetAccessible(true)でアクセス可能になります。

Class<?> personClass = Class.forName("Reflection.Person");
Object person = personClass.getConstructor(String.class).newInstance("Alice");

Field nameField = personClass.getDeclaredField("Name");
nameField.setAccessible(true);

// 値の取得
String currentName = (String) nameField.get(person);
System.out.println(currentName); // Alice

// 値の変更
nameField.set(person, "Bob");
System.out.println(((Person) person).getName()); // Bob

コンストラクタの動的利用

コンストラクタもリフレクションで取得・実行可能です。プライベートコンストラクタも同様に扱えます。

Class<Student> clazz = Student.class;

// publicコンストラクタ
Constructor<Student> publicCtor = clazz.getConstructor(String.class, String.class);
Student s1 = publicCtor.newInstance("Tom", "S001");

// privateコンストラクタ
Constructor<Student> privateCtor = clazz.getDeclaredConstructor(String.class);
privateCtor.setAccessible(true);
Student s2 = privateCtor.newInstance("Jerry");

System.out.println(s1.getName()); // Tom
System.out.println(s2.getName()); // Jerry

アノテーションの取得

リフレクションはアノテーション情報の取得にも使用されます。getAnnotation()メソッドで特定のアノテーションを取得できます。

Class<Student> clazz = Student.class;
CustomDescriptions annos = clazz.getAnnotation(CustomDescriptions.class);
if (annos != null) {
    for (CustomDescription desc : annos.value()) {
        System.out.println("description: " + desc.description());
    }
}
// 出力:
// description: 学生
// description: 人

タグ: Java Reflection Annotation

6月13日 23:04 投稿