1. 導入
Javaにおける java.lang.Class
2. 基礎知識
Javaのすべての型(クラス、インターフェース、プリミティブ、配列)には、対応する Classオブジェクト がJVM上に存在します。
- Reflection API: java.lang.reflectパッケージを使用し、実行時にクラスの構造(メソッド、フィールド)を調査・操作します。非常に強力ですが、型安全性が欠如しており、実行時のオーバーヘッドが大きいのが難点です。
- Method Handles: Java 7で導入された、メソッドを型安全かつ高速に呼び出すための機構です。ReflectionよりJVMの最適化を受けやすく、現代的なライブラリ開発ではこちらが推奨されます。
- VarHandles: Java 9で導入。フィールドに対する低レイテンシなアクセスや、アトミックな操作を可能にする機構です。
3. 実装/解決策
実務では「動的なメソッド実行」を行う際、ReflectionではなくMethodHandlesを利用することでパフォーマンスを向上させることが可能です。以下の手順が基本です。
1. Classオブジェクトを取得する。
2. MethodHandles.Lookup を使用してアクセス権を取得する。
3. MethodType を定義し、メソッドを検索する。
4. invokeExact または invoke で呼び出す。
4. サンプルプログラム
以下は、ReflectionとMethodHandlesの両方を用いた、動的なメソッド呼び出しのサンプルです。
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
public class MetaProgrammingDemo {
public void targetMethod(String msg) {
System.out.println(“呼び出されたメッセージ: ” + msg);
}
public static void main(String[] args) throws Throwable {
Class
MetaProgrammingDemo instance = new MetaProgrammingDemo();
// 1. 従来のReflectionによる呼び出し
Method method = clazz.getMethod(“targetMethod”, String.class);
method.invoke(instance, “Reflection方式”);
// 2. MethodHandlesによる高速な呼び出し
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType mt = MethodType.methodType(void.class, String.class);
MethodHandle mh = lookup.findVirtual(clazz, “targetMethod”, mt);
// bindToを使用してインスタンスを事前結合するとさらに効率的
mh.bindTo(instance).invoke(“MethodHandle方式”);
}
}
5. 応用・注意点
実務でこれらの技術を扱う際は、以下の点に注意してください。
- セキュリティとモジュール化: Java 9以降のモジュールシステム(JPMS)では、カプセル化が強化されています。`setAccessible(true)` を多用すると、将来的なJavaアップデートで動かなくなるリスクがあります。可能な限り MethodHandles を使用し、アクセス権の範囲内で操作することを推奨します。
- パフォーマンス: MethodHandleは、一度取得したものを static final フィールドなどにキャッシュすることで、呼び出しコストを大幅に削減できます。毎回 `findVirtual` を呼び出すのは避けてください。
- 例外処理: MethodHandleの実行は Throwable をスローするため、例外のハンドリングが少し煩雑になります。業務ロジックに組み込む際は、適切なラッパーメソッドを作成し、例外を抽象化することをお勧めします。

コメント