はじめに
プログラミングにおけるリフレクションとは、変数からメソッドの宣言まで、プログラムの内部構成のすべてを知ることのできる機能です。Javaでこの機能を利用するには、その名のとおり、JavaリフレクションAPIを使用します。
JavaリフレクションAPIを使用すると、特定のJava仮想マシン(JVM)のクラス、インターフェース、およびオブジェクトの内部情報を知ることができます。一般に、開発者はこのAPIを使用して次のような作業を行います。この作業内容を見れば、デバッガや統合開発環境(IDE)などのツールの開発にこのAPIが頻繁に使用される理由が分かると思います。
- オブジェクトのクラスを判別する。
- クラスの修飾子、フィールド、メソッド、コンストラクタなどに関する情報を得る。
- インターフェースの定数とメソッドの宣言に関する情報を得る。
- 実行時まで名前はわからないが、設計時に使用されたり、ランタイムパラメータとして与えられたりするクラスのインスタンスを作成する。
- 実行時まで名前のわからないオブジェクトのフィールド値を取得または設定する。
- オブジェクトのメソッドを呼び出す。実行時まで認識されないメソッドでも呼び出せる。
リフレクションの使用法を実感できるものとして、JavaBeansがあります。JavaBeansでは、ビルダツールを使用してソフトウェアコンポーネントを視覚的に操作できます。このビルダツールは、リフレクションを利用することで、Javaコンポーネント(クラス)が動的にロードされるときの各クラスのプロパティを取得しているのです。
リフレクションを使用してクラス動作を取得する
リフレクションを使用してクラスの動作を確認する方法を理解するために、Employee
クラスの単純な例を考えてみましょう。
public class Employee { public String empNum; public String empName; public Employee() { this( "1", "King"); } public Employee(String empNum, String empName) { empNum = empNum; empName = empName; } public String toString() { return "Employee Details: EmpNumber: " + empNum + ", EmpName: "+ empNum; } } import java.lang.reflect.Modifier; public class AnalyzeClass { public static void main(String[] args) { Employee employee = new Employee(); Class klass = employee.getClass(); System.out.println( "Class name: " + klass.getName()); System.out.println( "Class super class: " + klass.getSuperclass()); int mods = klass.getModifiers(); System.out.println( "Class is public: " + Modifier.isPublic(mods)); System.out.println( "Class is final: " + Modifier.isFinal(mods)); System.out.println( "Class is abstract: " + Modifier.isAbstract(mods)); } }
Modifier
クラスをコンパイルして、このAnalyzeClass
を実行すると、次のように出力されます。
Class name: Employee Class super class: class java.lang.Object Class is public: true Class is final: false Class is abstract: false
この内容は、基本的にEmployee
クラスを抽出したもので、このクラスが持つすべての特性を取得できています。まだどうも信用できないと思いますか? ではもう1つ、今度はMethod
クラスを使った例を考えてみましょう。
import java.lang.reflect.*; public class DumpMethods { public static void main(String args[]) { try { Class c = Class.forName(args[0]); Method m[] = c.getDeclaredMethods(); for (int i = 0; i < m.length; i++) System.out.println(m[i].toString()); } catch (Throwable e) { System.err.println(e); } } }
このコードをコンパイルし、次のように既知のクラスを引数として呼び出すと、
java DumpMethods java.util.Stack
結果は、次のようになります。
public synchronized java.lang.Object java.util.Stack.pop() public java.lang.Object java.util.Stack.push(java.lang.Object) public boolean java.util.Stack.empty() public synchronized java.lang.Object java.util.Stack.peek() public synchronized int java.util.Stack.search(java.lang.Object)
上記の出力では、java.util.Stack
クラスのすべてのメソッドが列挙されています。Method
は、java.lang.reflect
に含まれるクラスの1つで、このような結果をもたらす機能があります。